¿Cómo ejecutar las pruebas unitarias (MSTest) en paralelo?

Estoy buscando formas de ejecutar suites de prueba en paralelo.

Estoy al tanto de la configuración .testrunconfig . Esto le permite multiplexar en la cantidad de CPU.

Quiero ejecutar 1000 pruebas en paralelo. Esto tiene sentido porque estoy probando un servicio web, por lo que el 90% del tiempo dedicado a una prueba está esperando que el servicio responda.

¿Alguna idea sobre cómo llevarlo a cabo? Las pruebas están escritas para VS, pero estoy abierto a ejecutarlas fuera de VS.

Edición posterior : el equipo de prueba de Visual Studio lo agregó en la Actualización VS 1. VS. Ver la respuesta de Mark Sowul a continuación.

La mayoría de las respuestas en esta página olvidan mencionar que MSTest paraleliza las pruebas en ensamblajes separados . Tienes que dividir tus unittests en múltiples .dll para paralelizarlos.

¡Pero! La versión más reciente, MSTest V2, ahora PUEDE paralelizar “en ensamblaje” (¡yay!), Solo necesita instalar un par de paquetes nuget en su proyecto de prueba: TestFramework y TestAdapter, como se describe aquí https://blogs.msdn.microsoft .com / devops / 2018/01/30 / mstest-v2-in-assembly-parallel-test-execution /

Y luego simplemente agregue esto a su proyecto de prueba

 [assembly: Parallelize(Workers = 4, Scope = ExecutionScope.ClassLevel)] 

Puede obtener hasta 5 utilizando el método del Blog de prueba del equipo de Visual Studio

Tenga en cuenta que puede haber problemas de simultaneidad al usar esto, ya que MSTest no aísla completamente cada prueba (la estática se mantiene, por ejemplo, haciendo que las cosas sean interesantes para el código destinado a ejecutarse una vez).

(No hay idea de por qué el límite es 5, pero MSTest no los ejecutará en paralelo si parallelTestCount está configurado en más de 5. Según los comentarios a continuación, esta regla aparentemente cambia con Visual Studio 2013)

La actualización 1 de Visual Studio 2015 agrega esto. https://docs.microsoft.com/visualstudio/releasenotes/vs2015-update1-vs#misc

Para la Actualización 2, hay un botón de alternar UI en la barra de herramientas en la parte superior del panel del Explorador de Pruebas (entre los cuadros de ‘agrupamiento’ y ‘búsqueda’).

Para la Actualización 1, establezca lo siguiente en .runsettings

    0   

El valor de MaxCpuCount tiene la siguiente semántica:

• ‘n’ (donde 1 <= n <= número de núcleos): se iniciarán los procesos 'hasta' n '.

• ‘n’ de cualquier otro valor: la cantidad de procesos iniciados será tantos como los núcleos disponibles en la máquina.

Lo que encontré es que C: \ Archivos de progtwig (x86) \ Microsoft Visual Studio 11.0 \ Common7 \ IDE \ CommonExtensions \ Microsoft \ TestWindow \ vstest.console.exe ejecutará pruebas paralelas con un archivo .testsettings que se ve así:

   These are default test settings for a local test run.              

La referencia se puede encontrar aquí http://msdn.microsoft.com/en-us/library/vstudio/jj155796.aspx

Las respuestas anteriores definitivamente ayudaron a aclarar las cosas para mí, pero, este punto del blog de John Koerner: https://johnkoerner.com/vs2015/parallel-test-execution-in-visual-studio-2015-update-1-might-not -be-what-you-expect / era la parte que nos faltaba.

“La ejecución de prueba paralela aprovecha los núcleos disponibles en la máquina y se realiza iniciando el motor de ejecución de prueba en cada núcleo disponible como un proceso distinto y entregándole un contenedor (ensamblado, DLL o artefacto relevante que contiene las pruebas para ejecutar), pena de pruebas para ejecutar “.

-> “El bit de contenedor separado es la pieza que me faltaba. Para hacer que mis pruebas se ejecutaran en paralelo, tenía que dividir mis pruebas en ensamblajes de prueba separados. Después de hacerlo, vi que las pruebas se realizaban en diferentes ensamblajes. estaban corriendo en paralelo “.

Así que sí, hicimos que las pruebas se ejecutasen en paralelo en VSTS usando su práctica bandera ‘ejecutar en paralelo’, pero no fue suficiente, tuvimos que dividir nuestras pruebas en proyectos de prueba separados. Lógicamente agrupados por supuesto, no un proyecto por prueba que sería ridículo

  1. Asegúrese de que la primera columna en su DataTable sea una ID única.
  2. Cree un delegado AsyncExecutionTask que acepte una DataRow y no devuelva nada.
  3. Cree una clase estática (ParallelTesting) con un método AsyncExecutionContext que acepte un DataRow y un delegado AsyncExecutionTask.
  4. En la clase estática, agregue una propiedad estática BatchStarted.
  5. En la clase estática, agregue una propiedad estática AsyncExecutionTests Dictionary.
  6. En el método AsyncExecutionContext, agregue lo siguiente:

     public static void AsyncExecutionContext(DataRow currentRow, AsyncExecutionTask test) { if(!BatchStarted) { foreach(DataRow row in currentRow.Table) { Task testTask = new Task(()=> { test.Invoke(row); }); AsyncExecutionTests.Add(row[0].ToString(), testTask); testTask.Start(); } BatchStarted = true; } Task currentTestTask = AsyncExecutionTests[row[0].ToString()]; currentTestTask.Wait(); if(currentTestTask.Exception != null) throw currentTestTask.Exception; } 
  7. Ahora usa la clase así:

     [TestMethod] public void TestMethod1() { ParallelTesting.AsyncExecutionContext(TestContext.DataRow, (row)=> { //Test Logic goes here. } ); } 

Nota: Deberá realizar algunas modificaciones con las excepciones para que funcionen correctamente (es posible que tenga una excepción agregada, necesitará la primera excepción). La cantidad de tiempo que muestra ejecutar cada prueba ya no será precisa. También querrá limpiar la clase ParallelTesting después de que se complete la última fila.

Cómo funciona: la lógica de prueba se envuelve en una lambda y se pasa a una clase estática que ejecutará la lógica una vez para cada fila de datos de prueba cuando se llame por primera vez (primera fila ejecutada). Las llamadas sucesivas a la clase estática simplemente esperan a que finalice la tarea de prueba prearrancada.

De esta forma, cada llamada al marco de prueba realizado en TestMethod simplemente recostack los resultados de la prueba correspondiente que ya se ejecutó.

Posibles mejoras:

  • Haga que AsyncExecutionContext tome un parámetro maxSynchronousTasks.
  • Observe cómo el marco mueve trazas de stack completas a través del código no administrado para ver si la excepción Task.Exception se puede pasar al marco de prueba visual studio sin reiniciar y destruir el stacktrace.