¿De qué sirve la anotación @TestInstance en JUnit 5?

6 minutos de lectura

Avatar de usuario de Mahozad
Mahozad

¿Puede dar una explicación sencilla de @TestInstance anotación y cómo es útil en JUnit 5?

Creo que podemos lograr el mismo efecto probablemente por haciendo nuestros campos static.

avatar de usuario de glytching
glitching

pienso los documentos proporcionar un resumen útil:

Si prefiere que JUnit Jupiter ejecute todos los métodos de prueba en la misma instancia de prueba, simplemente anote su clase de prueba con @TestInstance(Lifecycle.PER_CLASS). Al usar este modo, se creará una nueva instancia de prueba una vez por clase de prueba. Por lo tanto, si sus métodos de prueba se basan en el estado almacenado en variables de instancia, es posible que deba restablecer ese estado en los métodos @BeforeEach o @AfterEach.

El modo “por clase” tiene algunos beneficios adicionales sobre el modo predeterminado “por método”. Específicamente, con el modo “por clase” es posible declarar @BeforeAll y @AfterAll en métodos no estáticos, así como en métodos predeterminados de la interfaz. Por lo tanto, el modo “por clase” también permite utilizar los métodos @BeforeAll y @AfterAll en las clases de prueba @Nested.

Pero probablemente ya haya leído eso y tenga razón al pensar que hacer que un campo sea estático tendrá el mismo efecto que declarar el campo como una variable de instancia y usar @TestInstance(Lifecycle.PER_CLASS).

Entonces, quizás la respuesta a la pregunta “cómo podría ser útil en JUnit 5” es que usar un @TestInstance

  • Sea explícito acerca de sus intenciones. Podría suponerse que el uso de la palabra clave static fue accidental mientras que el uso de @TestInstance es menos probable que sea accidental o el resultado de copiar y pegar sin pensar.
  • Delega la responsabilidad de administrar el alcance y el ciclo de vida y limpiar el marco en lugar de tener que recordar administrarlo usted mismo.

  • También es un requisito previo si desea crear pruebas parametrizadas con MethodSource dentro de clases de prueba anidadas. github.com/junit-team/junit5/issues/1229

    – Nitesh

    26 de septiembre de 2019 a las 12:01


  • Hacer que los miembros de la clase de prueba sean estáticos puede ser problemático con las jerarquías de clase. El polimorfismo le brinda algunas opciones geniales para escribir código más limpio y menos redundante. @TestInstance(PER_CLASS) debería ser el valor predeterminado en Júpiter en mi humilde opinión. Da como resultado un código de prueba mejor y más elástico y no tiene más que ventajas en comparación con la alternativa.

    – jannis

    23 de agosto de 2020 a las 9:54


Esta anotación se introdujo para reducir la cantidad de objetos creados al ejecutar las pruebas unitarias.

agregando @TestInstance(TestInstance.Lifecycle.PER_CLASS) a su clase de prueba evitará que se cree una nueva instancia de su clase para cada prueba en la clase. Esto es particularmente útil cuando tiene muchas pruebas en la misma clase de prueba y la creación de instancias de esta clase es costosa.

Esta anotación debe usarse con precaución. Todas las pruebas unitarias deben ser aisladas e independientes entre sí. Si una de las pruebas cambia el estado de la clase de prueba, entonces no debe usar esta función.

Hacer que sus campos sean estáticos para lograr el mismo efecto no es una buena idea. De hecho, reducirá la cantidad de objetos creados, pero no se pueden limpiar cuando se ejecutan todas las pruebas en la clase de prueba. Esto puede causar problemas cuando tiene un conjunto de pruebas gigante.

  • Me gusta esta respuesta porque aborda directamente una desventaja importante del uso de campos estáticos.

    – Nathan Hughes

    28 de septiembre de 2018 a las 12:07

  • @dyVeloper ¿Cuál será la anotación similar en testng?

    – gomathi subramaniano

    12 de septiembre a las 7:46


avatar de usuario de cassiomolin
casiomolin

@TestInstance se utiliza para configurar el ciclo de vida de las instancias de prueba para la clase de prueba anotada o la interfaz de prueba:

  • PER_CLASS: Se creará una nueva instancia de prueba una vez por clase de prueba.
  • PER_METHOD: Se creará una nueva instancia de prueba para cada método de prueba, método de fábrica de prueba o método de plantilla de prueba. Este modo es análogo al comportamiento encontrado en las versiones 1 a 4 de JUnit.

Si @TestInstance no se declara explícitamente en una clase de prueba o en una interfaz de prueba implementada por una clase de prueba, el modo de ciclo de vida se establecerá implícitamente de forma predeterminada en PER_METHOD.


Establecer el modo de ciclo de vida de la instancia de prueba en PER_CLASS habilita las siguientes características:

  • Estado de instancia de prueba compartido entre métodos de prueba en una clase de prueba determinada, así como entre métodos no estáticos @BeforeAll y @AfterAll métodos en la clase de prueba.
  • Declaración de @BeforeAll y @AfterAll métodos en @Nested clases de prueba
  • Declaración de @BeforeAll y @AfterAll en los métodos predeterminados de la interfaz.
  • Declaración simplificada de @BeforeAll y @AfterAll métodos en clases de prueba implementados con el lenguaje de programación Kotlin.

Ver el ciclo de vida de la instancia de prueba documentación para más detalles.

dado que nadie proporciona un ejemplo de codificación adecuado, me gustaría dar una muestra de código simple como se muestra a continuación para comprender el concepto,

Muestra por método: opción predeterminada en Junit5
Tenga en cuenta que dos métodos son estáticos; de lo contrario, se activará una excepción porque la clase crea una instancia en cada método.

@TestInstance(Lifecycle.PER_METHOD)
public class MathUtilTestPerMethod {

    MathUtil util;

    @BeforeAll
    static void beforeAllInit() {
        System.out.println("running before all");
    }

    @AfterAll
    static void afterAllCleanUp() {
        System.out.println("running after all");
    }

    @BeforeEach
    void init() {
        util = new MathUtil();
        System.out.println("running before each...");
    }

    @AfterEach
    void cleanUp() {
        System.out.println("running after each...");
    }

    @Test
    void testSum() {
        assertEquals(2, util.addtwoNumbers(1, 1));
    }

}

Muestra por clase
Tenga en cuenta que la estática se elimina de los dos métodos y el objeto MathUtil se crea globalmente, no en un método, porque la clase se instancia solo una vez.

@TestInstance(Lifecycle.PER_CLASS)
public class MathUtilTestPerClass {

    MathUtil util = new MathUtil();

    @BeforeAll
    void beforeAllInit() {
        System.out.println("running before all");
    }

    @AfterAll
    void afterAllCleanUp() {
        System.out.println("running after all");
    }

    @BeforeEach
    void init() {
        System.out.println("running before each...");
    }

    @AfterEach
    void cleanUp() {
        System.out.println("running after each...");
    }

    @Test
    void testSum() {
        assertEquals(2, util.addtwoNumbers(1, 1));
    }

}

Avatar de usuario de Mahozad
Mahozad

Esto también es útil cuando se escriben pruebas en kotlin (porque no tiene métodos estáticos).

Entonces, en lugar de usar un objeto complementario con @JvmStatic se divierte en eso para @BeforeAll o @AfterAllhacer el ciclo de vida PER_CLASS y anotar métodos regulares con @BeforeAll o @AfterAll:

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class MyTest {

    @BeforeAll
    fun setup() {
        println("I am invoked only once")
    }
}

Al usar este enfoque, tenga cuidado de restablecer las variables de su instancia en @BeforeEach o @AfterEach diversiones si es necesario.

Gracias a Este artículo por su ayuda.

¿Ha sido útil esta solución?