Pregunta Antes y después de la ejecución de la suite, enganche jUnit 4.x


Estoy tratando de preformar la configuración y el desmontaje para un conjunto de pruebas de integración, usando 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?

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


76
2017-09-17 13:07


origen


Respuestas:


Sí, es posible ejecutar de manera confiable los métodos de configuración y derribo antes y después de cualquier prueba en un banco 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 como:

package com.test;

import org.junit.Test;


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

}

... y puedes imaginar que Test2 tiene un aspecto similar. Si ejecutó TestSuite, obtendría:

setting up
test1
test2
tearing down

Entonces puede ver que la configuración / desmantelamiento solo se ejecuta 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 con las pruebas fallidas. Esto no se recomienda como una práctica continua, pero debería hacerlo funcionar hasta que todas sus pruebas pasen. Para más detalles, vea el maven la documentación surefire.


107
2017-10-07 02:51



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 RunListener solo configure el plugin surefire de la siguiente manera: http://maven.apache.org/surefire/maven-surefire-plugin/examples/junit.html sección "Uso de oyentes y reporteros personalizados"

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


31
2018-02-07 17:29



Puedes usar el @ClassRule anotación en JUnit 4.9+ como Describí en una respuesta otra pregunta.


11
2017-10-03 18:15



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()
    {

    }

}

8
2017-09-17 13:32



Aquí nosotros

  • actualizado a JUnit 4.5,
  • escribió anotaciones para etiquetar cada clase o método de prueba que necesitaba un servicio que funcionara,
  • escribieron manejadores 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 y agregó los métodos del controlador estático a la cadena de ejecución de la prueba en los puntos apropiados.

3
2018-04-01 18:13



Siempre que todas sus pruebas se extiendan a 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 puede usar @BeforeClass y @AfterClass dentro de subclases
  • si ejecuta solo una prueba en el paquete, la limpieza no está completa
  • ...

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


3
2017-09-27 15:51



En cuanto a "Nota: estamos utilizando 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, maven se detiene y no se ejecuta después de la prueba de integración , que no es de ayuda ".

puede probar el plugin de failsafe en su lugar, creo que tiene la facilidad para asegurar que la limpieza ocurra independientemente de la configuración o estado de etapa intermedia


2
2017-12-07 14:54



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 así en eclipse, así que no estoy seguro de lo portátil que es fuera de ese entorno


1
2017-09-17 13:50



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


0
2017-09-17 13:28



Dado que maven-surefire-plugin no ejecuta primero la clase Suite sino que trata las clases suite y de prueba de la misma manera, podemos configurar el siguiente complemento para habilitar solo las 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
2018-06-23 17:39



Si no desea crear una suite y tiene que enumerar todas sus clases de prueba, puede usar la función de reflexión para buscar dinámicamente la cantidad de clases de prueba y realizar la cuenta regresiva en una clase base @ AfterClass para hacer una sola 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 un indicador booleano para realizar el recuento de reflexión y probar la configuración solo 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 proviene de esta respuesta SO https://stackoverflow.com/a/37488620/5930242

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


0
2017-10-25 22:38