Pregunta ¿En qué orden están Junit @ Before / @ After call?


Tengo un paquete de prueba de integración. tengo un IntegrationTestBase clase para todas mis pruebas para extender. Esta clase base tiene un @Before (public void setUp()) y @After (public void tearDown()) método para establecer conexiones de API y DB. Lo que he estado haciendo es simplemente anular esos dos métodos en cada caso de prueba y llamadas super.setUp() y super.tearDown(). Sin embargo, esto puede causar problemas si alguien se olvida de llamar al súper o los coloca en el lugar equivocado y se lanza una excepción y se olvidan de llamar súper al final o algo así.

Lo que quiero hacer es hacer setUp y tearDown métodos en la clase base final y luego solo agrega nuestra propia anotada @Before y @After métodos. Al hacer algunas pruebas iniciales, parece que siempre llama en este orden:

Base @Before
Test @Before
Test
Test @After
Base @After

pero estoy un poco preocupado de que la orden no esté garantizada y de que pueda causar problemas. Miré a mi alrededor y no había visto nada sobre el tema. ¿Alguien sabe si puedo hacer eso y no tengo ningún problema?

Código:

public class IntegrationTestBase {

    @Before
    public final void setUp() { *always called 1st?* }

    @After
    public final void tearDown() { *always called last?* }
}


public class MyTest extends IntegrationTestBase {

    @Before
    public final void before() { *always called 2nd?* }

    @Test
    public void test() { *always called 3rd?* }

    @After
    public final void after() { *always called 4th?* }
}

106
2018-05-20 19:13


origen


Respuestas:


Sí, este comportamiento está garantizado:

@Before:

los @Before los métodos de las superclases se ejecutarán antes que los de la clase actual, a menos que se anulen en la clase actual. No se define ningún otro orden.

@After:

los @After los métodos declarados en superclases se ejecutarán después de los de la clase actual, a menos que se anulen en la clase actual.


107
2018-05-20 19:24



Un posible problema que me ha mordido antes:

Me gusta tener como máximo uno @Before método en cada clase de prueba, porque el orden de ejecución del @Before los métodos definidos dentro de una clase no están garantizados. Por lo general, voy a llamar a ese método setUpTest().

Pero aunque @Before está documentado como The @Before methods of superclasses will be run before those of the current class. No other ordering is defined., esto solo aplica si cada método marcado con @Before tiene un nombre único en la jerarquía de clases.

Por ejemplo, tuve lo siguiente:

public class AbstractFooTest {
  @Before
  public void setUpTest() { 
     ... 
  }
}

public void FooTest extends AbstractFooTest {
  @Before
  public void setUpTest() { 
    ...
  }
}

Esperaba AbstractFooTest.setUpTest() correr antes FooTest.setUpTest(), pero sólo FooTest.setupTest() Fue ejecutado. AbstractFooTest.setUpTest() no fue llamado en absoluto.

El código se debe modificar de la siguiente manera para que funcione:

public void FooTest extends AbstractFooTest {
  @Before
  public void setUpTest() {
    super.setUpTest();
    ...
  }
}

41
2018-06-20 00:51



Creo que basado en la documentación del @Before y @After la conclusión correcta es darles a los métodos nombres únicos. Uso el siguiente patrón en mis pruebas:

public abstract class AbstractBaseTest {

  @Before
  public final void baseSetUp() { // or any other meaningful name
    System.out.println("AbstractBaseTest.setUp");
  }

  @After
  public final void baseTearDown() { // or any other meaningful name
    System.out.println("AbstractBaseTest.tearDown");
  }
}

y

public class Test extends AbstractBaseTest {

  @Before
  public void setUp() {
    System.out.println("Test.setUp");
  }

  @After
  public void tearDown() {
    System.out.println("Test.tearDown");
  }

  @Test
  public void test1() throws Exception {
    System.out.println("test1");
  }

  @Test
  public void test2() throws Exception {
    System.out.println("test2");
  }
}

dar como resultado

AbstractBaseTest.setUp
Test.setUp
test1
Test.tearDown
AbstractBaseTest.tearDown
AbstractBaseTest.setUp
Test.setUp
test2
Test.tearDown
AbstractBaseTest.tearDown

Ventaja de este enfoque: los usuarios de la clase AbstractBaseTest no pueden anular los métodos setUp / tearDown por accidente. Si lo desean, necesitan saber el nombre exacto y pueden hacerlo.

(Menor) desventaja de este enfoque: los usuarios no pueden ver que hay cosas que suceden antes o después de su configuración / desvanecimiento. Necesitan saber que estas cosas son provistas por la clase abstracta. Pero supongo que esa es la razón por la que usan la clase abstracta


17
2017-07-09 13:58



Si cambia las cosas, puede declarar el resumen de la clase base y hacer que los descendientes declaren los métodos setUp y tearDown (sin anotaciones) a los que se llama en la clase base 'métodos anotados setUp y tearDown.


2
2018-05-20 19:21



Puedes usar @BeforeClass anotación para asegurar que setup() siempre se llama primero. Del mismo modo, puedes usar @AfterClass anotación para asegurar que tearDown()siempre se llama último.

Esto generalmente no se recomienda, pero es soportado.

No es exactamente lo que quiere, pero esencialmente mantendrá su conexión de base de datos abierta todo el tiempo en que se ejecutan las pruebas, y luego la cerrará de una vez por todas al final.


2
2018-05-20 19:26



Esta no es una respuesta a la pregunta del eslogan, pero es una respuesta a los problemas mencionados en el cuerpo de la pregunta. En lugar de usar @Before o @ After, mire en el uso @ org.junit.Rule porque te da más flexibilidad. ExternalResource (a partir de 4.7) es la regla que más le interesará si está administrando conexiones. Además, si desea un orden de ejecución garantizado de sus reglas, use un RuleChain (a partir de 4.10). Creo que todos estos estaban disponibles cuando se hizo esta pregunta. El siguiente ejemplo de código se copia de los javadocs de ExternalResource.

 public static class UsesExternalResource {
  Server myServer= new Server();

  @Rule
  public ExternalResource resource= new ExternalResource() {
      @Override
      protected void before() throws Throwable {
          myServer.connect();
         };

      @Override
      protected void after() {
          myServer.disconnect();
         };
     };

  @Test
  public void testFoo() {
      new Client().run(myServer);
     }
 }

2
2017-11-02 01:39