¿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 @BeforeClass
en 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
@Before
y@After
, puede usar@BeforeMethod
y@AfterMethod
respectivamente.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
@AfterClass
equivalente 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
@TestExecutionListeners
anotación. Algo como esta prueba:@RunWith(SpringJUnit4ClassRunner.class) @TestExecutionListeners({CustomTestExecutionListener.class, DependencyInjectionTestExecutionListener.class}) @ContextConfiguration("test-config.xml") public class DemoTest {
Spring
AbstractTestExecutionListener
contiene, 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
DependencyInjectionTestExecutionListener
al 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
/@AfterAllMethods
anotaciones 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
@Before
y los@After
métodos se llamarán 6 veces! Entonces en este contexto se@PostConstruct
comporta como una@Before
anotació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.@Test
ejecució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
init
que no sea estático porque cada prueba se ejecuta en una instancia separada. La instancia queinit
se 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
init
se llamará al método de subclase .fuente