JUnit siempre crea una instancia de la clase de prueba para cada método @Test. Esta es una decisión de diseño fundamental para facilitar la escritura de pruebas sin efectos secundarios. Las buenas pruebas no tienen dependencias de orden de ejecución (consulte FIRST ) y la creación de nuevas instancias de la clase de prueba y sus variables de instancia para cada prueba es crucial para lograrlo. Algunos marcos de prueba reutilizan la misma instancia de clase de prueba para todas las pruebas, lo que genera más posibilidades de crear accidentalmente efectos secundarios entre pruebas.
Y como cada método de prueba tiene su propia instancia, no tiene sentido que los métodos @ BeforeClass / @ AfterClass sean métodos de instancia. De lo contrario, ¿en cuál de las instancias de la clase de prueba deberían llamarse los métodos? Si fuera posible que los métodos @ BeforeClass / @ AfterClass hicieran referencia a variables de instancia, entonces solo uno de los métodos @Test tendría acceso a esas mismas variables de instancia (el resto tendría las variables de instancia en sus valores predeterminados) y @ El método de prueba se seleccionaría aleatoriamente, porque el orden de los métodos en el archivo .class no está especificado / depende del compilador (IIRC, la API de reflexión de Java devuelve los métodos en el mismo orden en que se declaran en el archivo .class, aunque también ese comportamiento no está especificado - he escrito una biblioteca para clasificarlos por sus números de línea).
Por lo tanto, hacer que esos métodos sean estáticos es la única solución razonable.
Aquí hay un ejemplo:
public class ExampleTest {
@BeforeClass
public static void beforeClass() {
System.out.println("beforeClass");
}
@AfterClass
public static void afterClass() {
System.out.println("afterClass");
}
@Before
public void before() {
System.out.println(this + "\tbefore");
}
@After
public void after() {
System.out.println(this + "\tafter");
}
@Test
public void test1() {
System.out.println(this + "\ttest1");
}
@Test
public void test2() {
System.out.println(this + "\ttest2");
}
@Test
public void test3() {
System.out.println(this + "\ttest3");
}
}
Que imprime:
beforeClass
ExampleTest@3358fd70 before
ExampleTest@3358fd70 test1
ExampleTest@3358fd70 after
ExampleTest@6293068a before
ExampleTest@6293068a test2
ExampleTest@6293068a after
ExampleTest@22928095 before
ExampleTest@22928095 test3
ExampleTest@22928095 after
afterClass
Como puede ver, cada una de las pruebas se ejecuta con su propia instancia. Lo que hace JUnit es básicamente lo mismo que esto:
ExampleTest.beforeClass();
ExampleTest t1 = new ExampleTest();
t1.before();
t1.test1();
t1.after();
ExampleTest t2 = new ExampleTest();
t2.before();
t2.test2();
t2.after();
ExampleTest t3 = new ExampleTest();
t3.before();
t3.test3();
t3.after();
ExampleTest.afterClass();
La respuesta corta es la siguiente: no hay una buena razón para que sea estático.
De hecho, convertirlo en estático causa todo tipo de problemas si utiliza Junit para ejecutar pruebas de integración DAO basadas en DBUnit. El requisito estático interfiere con la inyección de dependencias, el acceso al contexto de la aplicación, el manejo de recursos, el registro y cualquier cosa que dependa de "getClass".
fuente
@PostConstruct
para configurar y@AfterClass
derribar e ignoro las estáticas de Junit por completo. Para las pruebas DAO, luego escribí mi propiaTestCaseDataLoader
clase que invoco a partir de estos métodos.@PostConstruct
y@AfterClass
simplemente se comporta igual que@Before
y@After
. De hecho, sus métodos se llamarán para cada método de prueba y no una vez para toda la clase (como indica Esko Luontola en su respuesta, se crea una instancia de clase para cada método de prueba). No puedo ver la utilidad de su solución, así que (a menos que me pierda algo)La documentación de JUnit parece escasa, pero supongo: tal vez JUnit cree una nueva instancia de su clase de prueba antes de ejecutar cada caso de prueba, por lo que la única forma de que su estado de "fijación" persista en las ejecuciones es que sea estático, lo que puede ser ejecutado asegurándose de que su fixtureSetup (método @BeforeClass) sea estático.
fuente
Aunque esto no responderá a la pregunta original. Responderá al seguimiento obvio. Cómo crear una regla que funcione antes y después de una clase y antes y después de una prueba.
Para lograrlo puedes usar este patrón:
On before (Class) la JPAConnection crea la conexión una vez y después de (Class) la cierra.
getEntityManger
devuelve una clase interna deJPAConnection
que implementa el EntityManager de jpa y puede acceder a la conexión dentro deljpaConnection
. En antes (prueba) comienza una transacción después (prueba) la revierte nuevamente.Esto no es seguro para subprocesos, pero se puede hacer que lo sea.
Código seleccionado de
JPAConnection.class
fuente
Parece que JUnit crea una nueva instancia de la clase de prueba para cada método de prueba. Prueba este código
La salida es 0 0 0
Esto significa que si el método @BeforeClass no es estático, tendrá que ejecutarse antes de cada método de prueba y no habrá forma de diferenciar entre la semántica de @Before y @BeforeClass.
fuente
hay dos tipos de anotaciones:
por lo que @BeforeClass debe declararse estático porque se llama una vez. También debe considerar que ser estático es la única forma de garantizar la propagación adecuada del "estado" entre las pruebas (el modelo JUnit impone una instancia de prueba por @Test) y, dado que en Java solo los métodos estáticos pueden acceder a datos estáticos ... @BeforeClass y @ AfterClass solo se puede aplicar a métodos estáticos.
Esta prueba de ejemplo debería aclarar el uso de @BeforeClass vs @Before:
salida:
fuente
Según JUnit 5, parece que la filosofía de crear estrictamente una nueva instancia por método de prueba se ha relajado un poco. Han agregado una anotación que creará una instancia de una clase de prueba solo una vez. Por lo tanto, esta anotación también permite que los métodos anotados con @ BeforeAll / @ AfterAll (los reemplazos de @ BeforeClass / @ AfterClass) sean no estáticos. Entonces, una clase de prueba como esta:
imprimiría:
Por lo tanto, puede crear instancias de objetos una vez por clase de prueba. Por supuesto, esto hace que sea su responsabilidad evitar la mutación de objetos que se instancian de esta manera.
fuente
Para resolver este problema, simplemente cambie el método
a
y todo lo que se define en este método para
static
.fuente