it-swarm.dev

Enganche de ejecución antes y después de Suite en jUnit 4.x

Estoy intentando realizar la configuración y el desmontaje para un conjunto de pruebas de integración, utilizando jUnit 4.4 para ejecutar las pruebas. El desmontaje debe ejecutarse de forma fiable. Tengo otros problemas con TestNG, por lo que estoy buscando volver a jUnit. ¿Qué ganchos están disponibles para la ejecución antes de que se ejecuten las pruebas y después de que se hayan completado todas las pruebas?

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

81
sblundy

Sí, es posible ejecutar de manera confiable los métodos de configuración y eliminación antes y después de cualquier prueba en un conjunto de pruebas. Déjame 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");
    }

}

Entonces tu clase Test1 se vería algo así como:

package com.test;

import org.junit.Test;


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

}

... y te puedes imaginar que Test2 se ve similar. Si ejecuta TestSuite, obtendrá:

setting up
test1
test2
tearing down

Así que puede ver que la configuración/desmontaje solo se ejecuta antes y después de todas las pruebas, respectivamente.

El problema: esto solo funciona si está ejecutando el conjunto de pruebas y no ejecutando Test1 y Test2 como pruebas de JUnit individuales. Usted mencionó que está usando maven, y al plugin maven surefire le gusta ejecutar pruebas individualmente, y no 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 configurar maven.test.error.ignore para que la compilación continúe en las pruebas fallidas. Esto no se recomienda como práctica continua, pero debería hacer que funcione hasta que todas sus pruebas pasen. Para más detalles, vea la documentación de maven surefire .

109
Julie

Un colega mío sugirió lo siguiente: puede usar un RunListener personalizado e implementar el método testRunFinished (): http://junit.sourceforge.net/javadoc/org/junit/runner/notification/RunListener.html#testRunFinished ( org.junit.runner.Result)

Para registrar el RunListener, simplemente configure el complemento surefire de la siguiente manera: http://maven.Apache.org/surefire/maven-surefire-plugin/examples/junit.html section "Uso de escuchas y reporteros personalizados"

Esta configuración también debe ser elegida por el complemento de seguridad. 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 que todas las pruebas terminen.

31
Martin Vysny
11
ArtB

Usando anotaciones, puedes 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()
    {

    }

}
7
Jroc

Aquí nosotros

  • actualizado a JUnit 4.5,
  • escribí anotaciones para etiquetar cada clase de prueba o método que necesitaba un servicio funcional,
  • escribió controladores para cada anotación que contenía métodos estáticos para implementar la configuración y el desmontaje del servicio,
  • extendió el Runner habitual para ubicar las anotaciones en las pruebas, agregando los métodos de manejo estático en la cadena de ejecución de la prueba en los puntos apropiados.
3
carym

Siempre que todas sus pruebas puedan extender una clase "técnica" y estén en el mismo paquete, 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 muchos inconvenientes:

  • debe ejecutar todas las pruebas del paquete.
  • debe subclasificar una clase "techincal"
  • no se pueden usar las subclases @BeforeClass y @AfterClass
  • si ejecuta solo una prueba en el paquete, la limpieza no se realiza
  • ...

Para información: listClassesIn () => ¿Cómo encontrar todas las subclases de una clase dada en Java?

2
christophe blin

En cuanto a "Nota: estamos usando maven 2 para nuestra compilación. He intentado usar las fases de prueba previa y posterior a la integración de maven, pero, si falla una prueba, se detiene Maven y no se ejecuta la prueba posterior a la integración , que no sirve de ayuda ".

en su lugar, puede probar el complemento a prueba de fallos, creo que tiene la facilidad de garantizar que la limpieza se realice independientemente de la configuración o el estado de la etapa intermedia

2
Binod Pant

Si no desea crear una suite y tiene que enumerar todas sus clases de prueba, puede usar la reflexión para encontrar el número de clases de prueba dinámicamente y hacer una cuenta regresiva en una clase base @AfterClass para hacer el tearDown 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 usar @BeforeClass en lugar de los bloques estáticos, también puede usar una bandera booleana para realizar el conteo de reflejos y probar la configuración solo una vez en la primera llamada. Espero que esto ayude a alguien, me tomó una tarde descubrir 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 contábamos con una clase base para proporcionar algunas cosas comunes para todas nuestras pruebas, por lo que esta fue la mejor solución para nosotros.

La inspiración viene de este SO answer https://stackoverflow.com/a/37488620/5930242

Si no desea extender esta clase a todas partes, esta última SO respuesta puede hacer lo que quiera.

0
FredBoutin

Ya que maven-surefire-plugin no ejecuta la clase Suite primero, pero trata las clases de suite y prueba de la misma manera, por lo que podemos configurar el plugin como se muestra a continuación para habilitar solo clases de suite y deshabilitar 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>
0
Anurag Sharma

La única forma en la que creo que 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() {}  
} 

Uso algo como esto en Eclipse, así que no estoy seguro de cuán portátil es fuera de ese entorno.

0
Jroc

Por lo que sé, no hay ningún mecanismo para hacer esto en JUnit, sin embargo, puede intentar crear subclases de Suite y anular el método run () con una versión que proporcione enlaces.

0
user15299