¿Existen mejores prácticas para que Junit ejecute una función una vez en un archivo de prueba, y tampoco debería ser estático?
como @BeforeClassen la función no estática?
Aquí hay una fea solución:
@Before void init(){
if (init.get() == false){
init.set(true);
// do once block
}
}
Bueno, esto es algo que no quiero hacer y estoy buscando una solución junit integrada.

Respuestas:
Si no desea configurar inicializadores estáticos para una inicialización única y no es particular sobre el uso de JUnit, eche un vistazo a TestNG. TestNG admite la inicialización no estática de una sola vez con una variedad de opciones de configuración, todas usando anotaciones.
En TestNG, esto sería equivalente a:
@org.testng.annotations.BeforeClass public void setUpOnce() { // One time initialization. }Para desmontaje,
@org.testng.annotations.AfterClass public void tearDownOnce() { // One time tear down. }Para el equivalente TestNG de JUnit 4
@Beforey@After, puede usar@BeforeMethody@AfterMethodrespectivamente.fuente
Una simple declaración if también parece funcionar bastante bien:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:test-context.xml"}) public class myTest { public static boolean dbInit = false; @Autowired DbUtils dbUtils; @Before public void setUp(){ if(!dbInit){ dbUtils.dropTables(); dbUtils.createTables(); dbInit = true; } } ...fuente
@AfterClassequivalente no estático que se rompa después de que se hayan ejecutado todas las pruebas?Utilizar un constructor vacío es la solución más sencilla. Aún puede anular el constructor en la clase extendida.
Pero no es óptimo con toda la herencia. Es por eso que JUnit 4 usa anotaciones en su lugar.
Otra opción es crear un método auxiliar en una clase factory / util y dejar que ese método haga el trabajo.
Si está usando Spring, debería considerar usar la
@TestExecutionListenersanotación. Algo como esta prueba:@RunWith(SpringJUnit4ClassRunner.class) @TestExecutionListeners({CustomTestExecutionListener.class, DependencyInjectionTestExecutionListener.class}) @ContextConfiguration("test-config.xml") public class DemoTest {Spring
AbstractTestExecutionListenercontiene, por ejemplo, este método vacío que puede anular:public void beforeTestClass(TestContext testContext) throws Exception { /* no-op */ }NOTA: NO pase por alto / pase por alto
DependencyInjectionTestExecutionListeneral agregar personalizadoTestExecutionListeners. Si lo hace, todos los cables automáticos seránnull.fuente
beforeTestClass()llamará antes o después de la inicialización del contexto?Utilice fácilmente
@BeforeAllMethods/@AfterAllMethodsanotaciones para ejecutar un método dentro del contexto de la instancia (no estático), donde estarán disponibles todos los valores inyectados.Hay una biblioteca de pruebas especial para esto:
https://mvnrepository.com/artifact/org.bitbucket.radistao.test/before-after-spring-test-runner/0.1.0
https://bitbucket.org/radistao/before-after-spring-test-runner/
La única limitación: funciona solo para las pruebas de Spring .
(Soy el desarrollador de esta biblioteca de pruebas)
fuente
Nunca lo intenté, pero tal vez puedas crear un constructor sin argumentos y llamar a tu función desde allí.
fuente
El artículo analiza 2 soluciones muy buenas para este problema:
fuente
ACTUALIZACIÓN: Consulte el comentario de Cherry sobre por qué la sugerencia a continuación es defectuosa. (Mantengo la respuesta aquí en lugar de eliminarla, ya que el comentario puede proporcionar información útil a otros sobre por qué esto no funciona).
Otra opción que vale la pena considerar si se usa la inyección de dependencia (por ejemplo, Spring) es@PostConstruct. Esto garantizará que la inyección de dependencias esté completa, lo que no sería el caso en un constructor:@PostConstruct public void init() { // One-time initialization... }fuente
@Beforey los@Aftermétodos se llamarán 6 veces! Entonces en este contexto se@PostConstructcomporta como una@Beforeanotación. Simplemente puede probarlo: simplemente coloque 2 métodos de prueba en la clase de prueba, agregue@PostConstruct public void init() {System.out.println("started");}y vea en los registros cuántas veces se imprime.@Testejecución: "Para ejecutar el método, JUnit primero construye una instancia nueva de la clase y luego invoca el método anotado".Solo usa
@BeforeClass:@BeforeClass public static void init() { }No tiene sentido
initque no sea estático porque cada prueba se ejecuta en una instancia separada. La instancia queinitse ejecuta no coincidirá con la instancia de ninguna prueba.La única razón por la que puede querer que no sea estático es anularlo en subclases, pero también puede hacerlo con métodos estáticos. Simplemente use el mismo nombre, y solo
initse llamará al método de subclase .fuente