2010-06-21 22 views

Respuesta

61

Si está seguro de que realmente quiere hacer esto: puede haber una mejor manera, pero esto es todo lo que podía llegar a ...

junit4 tiene una anotación: @RunWith que permite anula el Runner predeterminado para tus pruebas.

En su caso, usted querrá crear una subclase especial de BlockJunit4ClassRunner, y anular computeTestMethods() para devolver las pruebas en el orden en que las quiere ejecutar. Por ejemplo, digamos que yo quiero para ejecutar mis pruebas en orden alfabético inverso:

public class OrderedRunner extends BlockJUnit4ClassRunner { 

    public OrderedRunner(Class klass) throws InitializationError { 
     super(klass); 
    } 

    @Override 
    protected List computeTestMethods() { 
     List list = super.computeTestMethods(); 
     List copy = new ArrayList(list); 
     Collections.sort(copy, new Comparator() { 
      public int compare(FrameworkMethod o1, FrameworkMethod o2) { 
       return o2.getName().compareTo(o1.getName()); 
      } 
     }); 
     return copy; 
    } 
}
@RunWith(OrderedRunner.class) 
public class OrderOfTest { 
    @Test public void testA() { System.out.println("A"); } 
    @Test public void testC() { System.out.println("C"); } 
    @Test public void testB() { System.out.println("B"); } 
}

Al ejecutar esta prueba produce:

C 
B 
A

para su caso específico, usted quiere un comparador que lo haría clasifique las pruebas por nombre en el orden en que las quiere ejecutar. (Sugeriría definir el comparador usando algo como la clase de Google Guava Ordering.explicit("methodName1","methodName2").onResultOf(...); donde onResultOf se proporciona una función que convierte FrameworkMethod a su nombre ... aunque obviamente usted es libre de implementar eso de cualquier manera que desee.

+0

Gracias por tomarse el tiempo para responder a esto Michael. –

+1

Eso es útil, ¡gracias! Por cierto, necesitaba hacer un pequeño cambio para compilarlo: "nuevo comparador()" -> "nuevo comparador ()" – kc2001

62

Puedo ver varios razones para hacer esto, especialmente cuando se utiliza JUnit para ejecutar pruebas funcionales o probar objetos persistentes. Por ejemplo, considere un objeto Article que persista en algún tipo de almacenamiento persistente. Si me gustaría probar la funcionalidad de inserción, actualización y eliminación en el Article objeto siguiendo el principio de la prueba de la unidad "todas las pruebas deben ser reorientables y probar solo una parte específica de la funcionalidad", tendría tres pruebas:

  • testInsertArticle()
  • testUpdateArticle()
  • testDeleteArticle()

Sin embargo, para poder probar la funcionalidad de actualización, me gustaría necesario insertar primero el artículo. Para probar la funcionalidad de eliminación, también necesitaría insertar un artículo. Por lo tanto, en la práctica, la funcionalidad de inserción ya se ha probado tanto en testUpdateArticle() como en testDeleteArticle(). Entonces es tentador simplemente crear un método de prueba testArticleFunctionality() que lo hace todo, pero los métodos de este tipo se volverán enormes (y no solo probarán parte de la funcionalidad del objeto Article).

Lo mismo vale para ejecutar pruebas funcionales contra, por ejemplo, una API relajante. JUnit también es excelente para estos casos si no fuera por el orden indeterminado de las pruebas.

Dicho esto, amplié Michael D's OrderedRunner para usar anotaciones para determinar el orden de las pruebas, solo pensé que debía compartirlas. Se puede ampliar aún más, por ejemplo, especificando exactamente de qué pruebas depende cada prueba, pero esto es lo que estoy usando por ahora.

Así es como se usa. Evita la necesidad de nombrar pruebas como AA_testInsert(), AB_testUpdate(), AC_testDelete(), ..., ZC_testFilter(), etc.

@RunWith(OrderedRunner.class) 
public class SomethingTest { 
    @Test 
    @Order(order=2) 
    public void testUpdateArticle() { 
     // test update 
    } 

    @Test 
    @Order(order=1) 
    public void testInsertArticle() { 
     // test insert 
    } 

    @Test 
    @Order(order=3) 
    public void testDeleteArticle() { 
     // test delete 
    } 
} 

No importa cómo estas pruebas se colocan en el archivo, siempre van a ser ejecutados como order=1 primera, order=2 segundo y último order=3, no importa si ellos se ejecutan desde dentro de Eclipse, utilizando Ant, o cualquier otra forma .

Implementación a continuación. Primero, la anotación Order.

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

Luego, modificó OrderedRunner.

public class OrderedRunner extends BlockJUnit4ClassRunner { 
    public OrderedRunner(Class<?> klass) throws InitializationError { 
     super(klass); 
    } 

    @Override 
    protected List<FrameworkMethod> computeTestMethods() { 
     List<FrameworkMethod> list = super.computeTestMethods(); 
     Collections.sort(list, new Comparator<FrameworkMethod>() { 
      @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 list; 
    } 
} 
+4

+1 para el orden basado en anotaciones en lugar de alfabéticamente – Matt

+1

Exactamente lo que quería encontrar . Podría haber sido mejor si el método de anotación fue 'value()' y simplemente escriba '@Order (1)' – lyomi

+0

He seguido su código, funciona muy bien, pero después de importar el mismo código a los casos de prueba que tiene 50 casos de prueba I tenía el error 'initializationerror0'. Estoy usando Kepler con JUnit4.10 – yashhy

25

Desde JUnit versión 4.11 en adelante, es posible influir en el orden de ejecución de la prueba al anotar su clase con @FixMethodOrder y especificar cualquiera de los MethodSorters disponibles. Vea el enlace this para más detalles.

4

Usando junit 4.11 la new annotation@FixMethodOrder permite establecer un orden específico:

@FixMethodOrder(MethodSorters.NAME_ASCENDING) 
+0

Así que, en mi caso, la razón por la que estoy buscando esto -similar al cartel de arriba y su objeto de "artículo" - es que si la primera prueba falla no se moleste en ejecutar las otras, ya que están usando una característica probada por la primera prueba. Para ese fin, lo que me gustaría es, si la primera prueba falla, que las pruebas restantes arrojen algo así como 'AssumptionViolatedException' (haciendo que las pruebas se etiqueten como 'omitidas' en mi corredor particular, intelliJ). Puedo hacer esto con if-statements y fields, pero me pregunto si JUnit tiene una facilidad mejor incorporada. ¿Alguna idea? – Groostav

+0

@Groostav Hay 'assumeTrue()'/'assumeThat()' etc. Puede hacer que la primera prueba establezca un booleano estático en la clase de prueba a 'true' si pasa y luego' assumeTrue (flag) 'en las otras pruebas , por ejemplo. O puede verificarlo solo una vez en un método '@ Before' (necesita otro indicador o un indicador de tres estados para omitir el control la primera vez antes de que se ejecute la primera prueba). –

1

Joscarsson y Michael D código en mi repo GitHub. Espero que no les importe. También proporciono la versión ordenada para la clase Parametrizada. Ya es para usar como dependencia maven

<repositories> 
    <repository> 
     <id>git-xxx</id> 
     <url>https://github.com/crsici/OrderedRunnerJunit4.11/raw/master/</url> 
    </repository> 
</repositories> 

<dependency> 
    <groupId>com.sici.org.junit</groupId> 
    <artifactId>ordered-runner</artifactId> 
    <version>0.0.1-RELEASE</version> 
</dependency> 
Cuestiones relacionadas