¿Cómo se ejecutan los métodos de prueba en un orden específico en JUnit4?

Quiero ejecutar métodos de prueba anotados por @Test en un orden específico.

Por ejemplo:

 public class MyTest { @Test public void test1(){} @Test public void test2(){} } 

Quiero asegurarme de ejecutar test1() antes de test2() cada vez que ejecuto MyTest , pero no pude encontrar una anotación como @Test(order=xx) .

Creo que es una característica bastante importante para JUnit, si el autor de JUnit no quiere la función de orden , ¿por qué?

Creo que es una característica bastante importante para JUnit, si el autor de JUnit no quiere la función de orden, ¿por qué?

No estoy seguro de que exista una forma clara de hacer esto con JUnit, según tengo entendido, JUnit supone que todas las pruebas se pueden realizar en un orden arbitrario. De las preguntas frecuentes:

¿Cómo uso un accesorio de prueba?

(…) El orden de las invocaciones de métodos de prueba no está garantizado , por lo que testOneItemCollection () podría ejecutarse antes de testEmptyCollection (). (…)

¿Por que es esto entonces? Bueno, creo que hacer que las pruebas ordenen es una práctica que los autores no quieren promocionar. Las pruebas deben ser independientes, no deben acoplarse y violar esto hará que las cosas sean más difíciles de mantener, romperá la capacidad de realizar pruebas individualmente (obviamente), etc.

Dicho eso, si realmente quieres ir en esta dirección, considera usar TestNG ya que admite ejecutar métodos de prueba en cualquier orden arbitrario de forma nativa (y cosas como especificar que los métodos dependen de grupos de métodos). Cedric Beust explica cómo hacer esto en orden de ejecución de pruebas en testng .

Si se deshace de su instancia existente de Junit y descarga JUnit 4.11 o superior en la ruta de comstackción, el siguiente código ejecutará los métodos de prueba en el orden de sus nombres, ordenados en orden ascendente:

 @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class SampleTest { @Test public void testAcreate() { System.out.println("first"); } @Test public void testBupdate() { System.out.println("second"); } @Test public void testCdelete() { System.out.println("third"); } } 

Si el pedido es importante, debe hacer el pedido usted mismo.

 @Test public void test1() { ... } @Test public void test2() { test1(); ... } 

En particular, debe listar algunas o todas las permutaciones de orden posibles para probar, si es necesario.

Por ejemplo,

 void test1(); void test2(); void test3(); @Test public void testOrder1() { test1(); test3(); } @Test(expected = Exception.class) public void testOrder2() { test2(); test3(); test1(); } @Test(expected = NullPointerException.class) public void testOrder3() { test3(); test1(); test2(); } 

O bien, una prueba completa de todas las permutaciones:

 @Test public void testAllOrders() { for (Object[] sample: permute(1, 2, 3)) { for (Object index: sample) { switch (((Integer) index).intValue()) { case 1: test1(); break; case 2: test2(); break; case 3: test3(); break; } } } } 

Aquí, permute() es una función simple que itera todas las permuaciones posibles en una colección de matriz.

La migración a TestNG parece ser la mejor, pero no veo una solución clara para jUnit. Aquí está la solución / formato más legible que encontré para jUnit:

 @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class SampleTest { @Test void stage1_prepareAndTest(){}; @Test void stage2_checkSomething(){}; @Test void stage2_checkSomethingElse(){}; @Test void stage3_thisDependsOnStage2(){}; @Test void callTimeDoesntMatter(){} } 

Esto garantiza que los métodos stage2 se invoquen después de los stage1 ones y antes de stage3 ones.

Es uno de los principales problemas que enfrenté cuando trabajé en Junit y se me ocurrió la siguiente solución que funciona bien para mí:

 import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import org.junit.runners.BlockJUnit4ClassRunner; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.InitializationError; public class OrderedRunner extends BlockJUnit4ClassRunner { public OrderedRunner(Class< ?> clazz) throws InitializationError { super(clazz); } @Override protected List computeTestMethods() { List list = super.computeTestMethods(); List copy = new ArrayList(list); Collections.sort(copy, new Comparator() { @Override public int compare(FrameworkMethod f1, FrameworkMethod f2) { Order o1 = f1.getAnnotation(Order.class); Order o2 = f2.getAnnotation(Order.class); if (o1 == null || o2 == null) { return -1; } return o1.order() - o2.order(); } }); return copy; } } 

también crea una interfaz como la siguiente:

  @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.METHOD}) public @interface Order { public int order(); } 

Ahora supongamos que tiene la clase A en la que ha escrito varios casos de prueba, como a continuación:

 (@runWith=OrderRunner.class) Class A{ @Test @Order(order = 1) void method(){ //do something } } 

Entonces la ejecución comenzará desde el método llamado “método ()”. ¡Gracias!

El cambio (aún no publicado) https://github.com/junit-team/junit/pull/386 introduce un @SortMethodsWith . https://github.com/junit-team/junit/pull/293 al menos hizo que el orden fuera predecible sin eso (en Java 7 puede ser bastante aleatorio).

Mira un informe JUnit. JUnit ya está organizado por paquete. Cada paquete tiene (o puede tener) clases TestSuite, cada una de las cuales a su vez ejecuta múltiples TestCases. Cada TestCase puede tener múltiples métodos de prueba del formulario public void test*() , cada uno de los cuales se convertirá realmente en una instancia de la clase TestCase a la que pertenecen. Cada método de prueba (instancia de TestCase) tiene un nombre y un criterio de aprobado / rechazado.

Lo que mi gestión requiere es el concepto de elementos TestStep individuales, cada uno de los cuales informa sus propios criterios de aprobado / rechazado . La falla de cualquier paso de prueba no debe impedir la ejecución de los pasos de prueba posteriores.

En el pasado, los desarrolladores de prueba en mi posición organizaban las clases de TestCase en paquetes que corresponden a la (s) parte (s) del producto bajo prueba, creaban una clase TestCase para cada prueba y convertían cada método de prueba en un “paso” separado en la prueba. completar con su propio criterio de aprobación / falla en la salida JUnit. Cada TestCase es una “prueba” independiente, pero los métodos individuales, o “pasos” de prueba dentro del TestCase, deben ocurrir en un orden específico.

Los métodos TestCase fueron los pasos del TestCase, y los diseñadores de prueba obtuvieron un criterio de aprobación / falla por cada paso de prueba. Ahora los pasos de la prueba son confusos y las pruebas (por supuesto) fallan.

Por ejemplo:

 Class testStateChanges extends TestCase public void testCreateObjectPlacesTheObjectInStateA() public void testTransitionToStateBAndValidateStateB() public void testTransitionToStateCAndValidateStateC() public void testTryToDeleteObjectinStateCAndValidateObjectStillExists() public void testTransitionToStateAAndValidateStateA() public void testDeleteObjectInStateAAndObjectDoesNotExist() public void cleanupIfAnythingWentWrong() 

Cada método de prueba afirma e informa sus propios criterios de aprobado / rechazado. Al colapsar esto en “un gran método de prueba” para ordenar, se pierde la granularidad de los criterios de aprobación / falla de cada “paso” en el informe de resumen JUnit. … y eso molesta a mis gerentes. Actualmente están demandando otra alternativa.

¿Alguien puede explicar cómo un JUnit con orden de método de prueba codificada podría soportar criterios de aprobación / falla por separado de cada paso de prueba secuencial, como se ejemplificó anteriormente y es requerido por mi administración?

Independientemente de la documentación, veo esto como una seria regresión en el marco de JUnit que está dificultando la vida para muchos desarrolladores de pruebas.

Lo que quiere es perfectamente razonable cuando los casos de prueba se ejecutan como un conjunto.

Lamentablemente, no hay tiempo para dar una solución completa en este momento, pero eche un vistazo a la clase:

 org.junit.runners.Suite 

Lo que le permite llamar casos de prueba (de cualquier clase de prueba) en un orden específico.

Estos pueden usarse para crear pruebas funcionales, de integración o de sistema.

Esto deja las pruebas de su unidad como están sin un orden específico (como se recomienda), ya sea que las ejecute así o no, y luego reutilice las pruebas como parte de una imagen más grande.

Reutilizamos / heredamos el mismo código para unidades, integración y pruebas del sistema, a veces impulsados ​​por datos, a veces impulsados ​​por el compromiso y, a veces, ejecutados como un conjunto de aplicaciones.

No estoy seguro de estar de acuerdo. Si deseo probar ‘Carga de archivos’ y luego probar ‘Datos insertados por carga de archivos’, ¿por qué no quiero que estos sean independientes el uno del otro? Perfectamente razonable, creo que puedo ejecutarlos por separado en lugar de tener ambos en un caso de prueba Goliath.

Vea mi solución aquí: “Junit y Java 7.”

En este artículo, describo cómo ejecutar pruebas junit en orden, “al igual que en su código fuente”. Se ejecutarán pruebas para que los métodos de prueba aparezcan en el archivo de clase.

http://intellijava.blogspot.com/2012/05/junit-and-java-7.html

Pero, como dijo Pascal Thivent, esta no es una buena práctica.

He leído algunas respuestas y estoy de acuerdo en que no es la mejor práctica, pero la forma más fácil de ordenar las pruebas, y la forma en que JUnit ejecuta las pruebas por defecto es por orden alfabético ascendente.

Así que solo nombre sus pruebas en el orden alfabético que desee. También tenga en cuenta que el nombre de la prueba debe comenzar con la palabra prueba. Solo ten cuidado con los números

test12 se ejecutará antes de test2

asi que:

testA_MyFirstTest testC_ThirdTest testB_ATestThatRunsSecond

Por favor revisa este: https://github.com/TransparentMarket/junit . Ejecuta la prueba en el orden en que se especifica (definida dentro del archivo de clase comstackdo). También presenta un conjunto de AllTests para ejecutar primero las pruebas definidas por el sub paquete. Al usar la implementación de AllTests, se puede ampliar la solución también al filtrar las propiedades (antes usábamos las anotaciones @Fast, pero aún no se habían publicado).

Aquí hay una extensión de JUnit que puede producir el comportamiento deseado: https://github.com/aafuks/aaf-junit

Sé que esto va en contra de los autores de la filosofía JUnit, pero cuando se utiliza JUnit en entornos que no son pruebas unitarias estrictas (como se practica en Java), esto puede ser muy útil.

Terminé pensando que mis pruebas no se corrieron en orden, pero la verdad es que el desastre fue en mis trabajos asincrónicos. Cuando se trabaja con simultaneidad, debe realizar comprobaciones de concurrencia entre sus pruebas también. En mi caso, los trabajos y las pruebas comparten un semáforo, por lo que las próximas pruebas se suspenden hasta que el trabajo en ejecución libere el locking.

Sé que esto no está completamente relacionado con esta pregunta, pero tal vez podría ayudar a orientar el problema correcto

puedes usar uno de estos códigos:

 @FixMethodOrder(MethodSorters.JVM)OR `@FixMethodOrder(MethodSorters.DEFAULT)` OR `@FixMethodOrder(MethodSorters.NAME_ASCENDING)` before your test class like this: @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class BookTest { ...} 

JUnit actualmente permite que los métodos de prueba ejecuten pedidos utilizando anotaciones de clase:

 @FixMethodOrder(MethodSorters.NAME_ASCENDING) @FixMethodOrder(MethodSorters.JVM) @FixMethodOrder(MethodSorters.DEFAULT) 

Para establecer el orden de los métodos, puede nombrarlos como:

a_testWorkUnit_WithCertainState_ShouldDoSomething b_testWorkUnit_WithCertainState_ShouldDoSomething c_testWorkUnit_WithCertainState_ShouldDoSomething

Puedes encontrar ejemplos aquí .