2008-09-17 10 views
74

Estoy tratando de preformar la configuración y el desmontaje de un conjunto de pruebas de integración, utilizando jUnit 4.4 para ejecutar las pruebas. El desmontaje debe ejecutarse de manera confiable. Estoy teniendo otros problemas con TestNG, así que estoy buscando un puerto de regreso a jUnit. ¿Qué anzuelos están disponibles para su ejecución antes de que se ejecuten las pruebas y después de que se hayan completado todas las pruebas?Antes y después de la ejecución de la serie enganche en jUnit 4.x

Nota: estamos utilizando maven 2 para nuestra compilación. He intentado usar las fases pre-pre- de maven & post-integration-test fases, pero, si falla una prueba, maven se detiene y no ejecuta post-integration-test, lo que no sirve de nada.

+1

Para las pruebas de integración, debe usar [maven-failsafe-plugin] (http://maven.apache.org/surefire/maven-failsafe-plugin/) en lugar de surefire. Esto no omitirá 'post-integration-test' si falla una prueba. Ver también [esta página wiki] (http://docs.codehaus.org/display/MAVENUSER/Maven+and+Integration+Testing). –

Respuesta

0

Por lo que yo sé, no hay ningún mecanismo para hacer esto en JUnit, sin embargo, podría intentar subclasificar Suite y reemplazar el método run() con una versión que proporcione ganchos.

+0

¿Es eso posible en Maven? – sblundy

7

El uso de anotaciones, se puede hacer algo como esto:

import org.junit.*; 
import static org.junit.Assert.*; 
import java.util.*; 

class SomethingUnitTest { 
    @BeforeClass 
    public static void runBeforeClass() 
    { 

    } 

    @AfterClass 
    public static void runAfterClass() 
    { 

    } 

    @Before 
    public void setUp() 
    { 

    } 

    @After 
    public void tearDown() 
    { 

    } 

    @Test 
    public void testSomethingOrOther() 
    { 

    } 

} 
+2

La instalación y el desmontaje deben ejecutarse una vez por ejecución. Esto solo ayudaría si todas las pruebas están en una clase. – sblundy

1

La única forma en que pienso entonces para obtener la funcionalidad que desea sería hacer algo como

import junit.framework.Test; 
import junit.framework.TestResult; 
import junit.framework.TestSuite; 

public class AllTests { 
    public static Test suite() { 
     TestSuite suite = new TestSuite("TestEverything"); 
     //$JUnit-BEGIN$ 
     suite.addTestSuite(TestOne.class); 
     suite.addTestSuite(TestTwo.class); 
     suite.addTestSuite(TestThree.class); 
     //$JUnit-END$ 
    } 

    public static void main(String[] args) 
    { 
     AllTests test = new AllTests(); 
     Test testCase = test.suite(); 
     TestResult result = new TestResult(); 
     setUp(); 
     testCase.run(result); 
     tearDown(); 
    } 
    public void setUp() {} 
    public void tearDown() {} 
} 

utilizo algo como esto en eclipse, entonces no estoy seguro qué tan portátil es fuera de ese entorno

+2

Este es un ejemplo para JUnit3, y OP solicitó JUnit4, pero solo en caso de que algunos usuarios de JUnit3 encuentren esta pregunta ... Para JUnit3, sería mejor deshacerse del método main() y tener el conjunto() Método Envuelva TestSuite en una subclase de junit.extensions.TestSetup. Todavía tiene las mismas advertencias que el ejemplo de Julie sobre ejecutar las clases de prueba individuales en su IDE. – NamshubWriter

103

Sí, es posible ejecutar de manera confiable los métodos de configuración y desmontaje antes y después de cualquier prueba en un banco de pruebas. Permítanme demostrar en código:

package com.test; 

import org.junit.AfterClass; 
import org.junit.BeforeClass; 
import org.junit.runner.RunWith; 
import org.junit.runners.Suite; 
import org.junit.runners.Suite.SuiteClasses; 

@RunWith(Suite.class) 
@SuiteClasses({Test1.class, Test2.class}) 
public class TestSuite { 

    @BeforeClass 
    public static void setUp() { 
     System.out.println("setting up"); 
    } 

    @AfterClass 
    public static void tearDown() { 
     System.out.println("tearing down"); 
    } 

} 

Por lo que su clase Prueba1 sería algo como:

package com.test; 

import org.junit.Test; 


public class Test1 { 
    @Test 
    public void test1() { 
     System.out.println("test1"); 
    } 

} 

... y se puede imaginar que Prueba2 tiene una apariencia similar. Si ejecutó TestSuite, se llega a:

setting up 
test1 
test2 
tearing down 

Así se puede ver que la puesta en marcha/derribe sólo se ejecutan antes y después de todas las pruebas, respectivamente.

El truco: esto solo funciona si está ejecutando el conjunto de pruebas, y no ejecuta Test1 y Test2 como pruebas JUnit individuales. Mencionaste que estás usando maven, y al plugin maven surefire le gusta realizar pruebas individualmente, y no formar parte de una suite. En este caso, recomendaría crear una superclase que extienda cada clase de prueba. La superclase contiene los métodos anotados @BeforeClass y @AfterClass. Aunque no es tan limpio como el método anterior, creo que funcionará para usted.

En cuanto al problema con las pruebas fallidas, puede establecer maven.test.error.ignore para que la compilación continúe en las pruebas fallidas. Esto no se recomienda como una práctica continua, pero debería hacerlo funcionar hasta que todas sus pruebas pasen. Para obtener más detalles, consulte maven surefire documentation.

+1

Esto funcionó perfectamente para mí una vez que entré en el plugin maven-surefire y creé una lista que apuntaba a la suite que quería ejecutar. – Jherico

+0

A partir de JUnit 4.8.2, esto no funciona bien con las pruebas parametrizadas. Los métodos @BeforeClass de la Suite se ejecutarán _después_ del método @ Parameterized.Parameters de la prueba, evitando cualquier dependencia de la configuración de la Suite. – Anm

+0

En respuesta a mí, al usar @Teorías, la llamada al método @DataPoints es llamada _después_ la @BeforeClass de la Suite. – Anm

3

Aquí,

  • pasaron a JUnit 4.5,
  • escribió anotaciones para etiquetar cada clase de prueba o método que necesita un servicio de trabajo,
  • escribió manipuladores para cada anotación que contenía los métodos estáticos para implementar el montaje y desmontaje del servicio,
  • amplió el corredor habitual ubique las anotaciones en las pruebas, agregando los métodos del controlador estático a la cadena de ejecución de la prueba en los puntos apropiados.
0

Dado que maven-surefire-plugin no ejecuta primero la clase Suite sino que trata las clases en suite y de prueba, podemos configurar el complemento como se indica a continuación para habilitar solo las clases de suite y desactivar todas las pruebas. Suite ejecutará todas las pruebas.

 <plugin> 
      <groupId>org.apache.maven.plugins</groupId> 
      <artifactId>maven-surefire-plugin</artifactId> 
      <version>2.5</version> 
      <configuration> 
       <includes> 
        <include>**/*Suite.java</include> 
       </includes> 
       <excludes> 
        <exclude>**/*Test.java</exclude> 
        <exclude>**/*Tests.java</exclude> 
       </excludes> 
      </configuration> 
     </plugin> 
2

En cuanto a la "Nota: estamos utilizando Maven 2 para nuestra acumulación He intentado usar pre & las fases posteriores a la integración de la prueba de Maven, pero, si no pasa la prueba, experto detiene y doesn'. ejecutar post-integración-prueba, que no es de ayuda ".

puede intentar la prueba de fallos-plugin en cambio, creo que tiene la instalación para asegurar la limpieza se produce independientemente de la configuración o de la etapa intermedia de estado

+0

Sí, el complemento a prueba de fallas le permitirá especificar la configuración y el desmontaje específicos. Aunque no creo que existiera falla en el momento en que se publicó esta pregunta. –

3

siempre que todos sus exámenes pueden extender una clase de "técnica" y se encuentran en el mismo paquete, se puede hacer un pequeño truco:

public class AbstractTest { 
    private static int nbTests = listClassesIn(<package>).size(); 
    private static int curTest = 0; 

    @BeforeClass 
    public static void incCurTest() { curTest++; } 

    @AfterClass 
    public static void closeTestSuite() { 
     if (curTest == nbTests) { /*cleaning*/ }    
    } 
} 

public class Test1 extends AbstractTest { 
    @Test 
    public void check() {} 
} 
public class Test2 extends AbstractTest { 
    @Test 
    public void check() {} 
} 

tenga en cuenta que esta solución tiene un montón de inconvenientes:

  • debe ejecutar todas las pruebas del paquete
  • debe subclase de una clase "techincal"
  • no se puede utilizar @BeforeClass y @AfterClass dentro subclases
  • si se ejecuta una sola prueba en el paquete, limpieza no se hace
  • ...

Para información: listClassesIn() =>How do you find all subclasses of a given class in Java?

+0

esto no es cierto en lo que mis propias pruebas muestran. Tengo una súper clase que inicia un glassfish incrustado en beforeclass y lo apaga después de clase. Tengo entonces 2 clases que se extienden desde esa súper clase. La clase previa se ejecuta antes de ejecutar las pruebas definidas en cada clase. –

28

Un colega mío sugirió lo siguiente: se puede utilizar un RunListener personalizada y poner en práctica el método testRunFinished(): http://junit.sourceforge.net/javadoc/org/junit/runner/notification/RunListener.html#testRunFinished(org.junit.runner.Result)

Para registrar el RunListener acaba de configurar el plugin de éxito seguro de la siguiente manera: http://maven.apache.org/surefire/maven-surefire-plugin/examples/junit.html sección "Utilización de detectores personalizados y reporteros "

Esta configuración también debe ser elegida por el complemento failsafe. Esta solución es excelente porque no tiene que especificar suites, clases de prueba de búsqueda ni nada de esto: le permite a Maven hacer su magia, esperando a que finalicen todas las pruebas.

+5

+1 ¡Esa es la primera solución utilizable que he visto sin el engorroso mantenimiento de una clase de suites! –

0

Si no desea crear un conjunto y tiene que enumerar todas sus clases de prueba, puede usar el reflejo para buscar dinámicamente el número de clases de prueba y realizar una cuenta regresiva en una clase base @ AfterClass para hacer el corte solo una vez:

public class BaseTestClass 
{ 
    private static int testClassToRun = 0; 

    // Counting the classes to run so that we can do the tear down only once 
    static { 
     try { 
      Field field = ClassLoader.class.getDeclaredField("classes"); 
      field.setAccessible(true); 

      @SuppressWarnings({ "unchecked", "rawtypes" }) 
      Vector<Class> classes = (Vector<Class>) field.get(BlockJUnit4ClassRunner.class.getClassLoader()); 
      for (Class<?> clazz : classes) { 
       if (clazz.getName().endsWith("Test")) { 
        testClassToRun++; 
       } 
      } 
     } catch (Exception ignore) { 
     } 
    } 

    // Setup that needs to be done only once 
    static { 
     // one time set up 
    } 

    @AfterClass 
    public static void baseTearDown() throws Exception 
    { 
     if (--testClassToRun == 0) { 
      // one time clean up 
     } 
    } 
} 

Si prefiere utilizar @BeforeClass en lugar de los bloques estáticos, también se puede utilizar un indicador booleano que hacer el recuento de la reflexión y la configuración de la prueba sólo una vez en la primera llamada. Espero que esto ayude a alguien, me tomó una tarde encontrar una manera mejor que enumerar todas las clases en una suite.

Ahora todo lo que necesita hacer es extender esta clase para todas sus clases de prueba. Ya teníamos una clase base para proporcionar algunas cosas en común para todas nuestras pruebas, así que esta era la mejor solución para nosotros.

La inspiración viene de la presente OS responder https://stackoverflow.com/a/37488620/5930242

Si no desea extender esta clase en todas partes, esta última respuesta, así que puede hacer lo que quiera.

Cuestiones relacionadas