java - debug - testng test
@BeforeClass and inheritance-orden de ejecuciĆ³n (14)
Tengo una clase base abstracta, que utilizo como base para mis pruebas unitarias (TestNG 5.10). En esta clase, inicializo todo el entorno para mis pruebas, estableciendo mapeos de bases de datos, etc. Esta clase abstracta tiene un método con una anotación @BeforeClass
que realiza la inicialización.
A continuación, @Test
esa clase con clases específicas en las que tengo métodos @Test
y también métodos @BeforeClass
. Estos métodos hacen la inicialización del entorno específica de la clase (por ejemplo, poner algunos registros en la base de datos).
¿Cómo puedo aplicar un orden específico de los métodos anotados @BeforeClass
? Necesito que los de la clase base abstracta se ejecuten antes que los de la clase extendida.
Ejemplo:
abstract class A {
@BeforeClass
doInitialization() {...}
}
class B extends A {
@BeforeClass
doSpecificInitialization() {...}
@Test
doTests() {...}
}
Orden esperado:
A.doInitialization
B.doSpecificInitialization
B.doTests
Orden real:
B.doSpecificInitialization // <- crashes, as the base init is missing
(A.doInitialization // <---not executed
B.doTests) // <-/
¿Por qué no intentas crear un método abstracto doSpecialInit () en tu súper clase, llamado desde tu método anotado BeforeClass en superclase?
Entonces los desarrolladores que heredan su clase se ven obligados a implementar este método.
¿Qué tal si tu método @BeforeClass llama a un método emptyBeforeClass () vacío que puede ser sobrescrito o no por subclases como sigue?
public class AbstractTestClass {
@BeforeClass
public void generalBeforeClass() {
// do stuff
specificBeforeClass();
}
protected void specificBeforeClass() {}
}
public class SpecificTest {
@Override
protected void specificBeforeClass() {
// Do specific stuff
}
// Tests
}
Añadí public
a la clase abstracta y TestNG (6.0.1) ejecutó doInitialization () antes de doTests
. TestNG no ejecuta doInitialization()
si doInitialization()
public
de la clase A.
public abstract class A {
@BeforeClass
doInitialization() {...}
}
class B extends A {
@Test
doTests() {...}
}
Acabo de pasar por esto y encontré una forma más de lograr esto. Solo use alwaysRun
en @BeforeClass
o @BeforeMethod
en la clase abstracta, funciona como es de esperar.
public class AbstractTestClass {
@BeforeClass(alwaysRun = true)
public void generalBeforeClass() {
// do stuff
specificBeforeClass();
}
}
Acabo de probar tu ejemplo con 5.11 y obtengo primero @BeforeClass de la clase base invocada.
¿Puedes publicar tu archivo testng.xml? Tal vez estés especificando A y B allí, mientras que solo B es necesario.
Siéntase libre de hacer un seguimiento de la lista de correo de usuarios de testng y podemos analizar su problema de cerca.
- Cedric
Cuando ejecuto desde: JUnitCore.runClasses (TestClass.class); Ejecutará el elemento primario correctamente, antes que el elemento secundario (No necesita super.SetUpBeforeClass (); ) Si lo ejecuta desde Eclipse: Por algún motivo, no ejecuta la clase base. El rodeo : llame explícitamente a la clase base: ( BaseTest.setUpBeforeClass (); ) Puede querer tener un indicador en la clase base en caso de que lo ejecute desde una aplicación, para determinar si ya está configurado o no. Por lo tanto, solo se ejecuta una vez si lo ejecuta a través de ambos métodos posibles (por ejemplo, desde eclipse para pruebas personales, y a través de ANT para una versión de compilación).
Esto parece ser un error con Eclipse, o al menos resultados inesperados.
En mi caso (JUnit) tengo los mismos métodos llamados setup () en la clase base y la clase derivada. En este caso, solo se llama al método de la clase derivada, y lo hago llamar al método de clase base.
Hay otra solución fácil aquí.
Mi situación particular es que necesito inyectar servicios simulados desde "BeforeClass" en la subclase antes de que se ejecute "BeforeClass" en la superclase.
Para hacer esto, simplemente use una @ClassRule
en la subclase.
Por ejemplo:
@ClassRule
public static ExternalResource mocksInjector = new ExternalResource() {
@Override
protected void before() {
// inject my mock services here
// Note: this is executed before the parent class @BeforeClass
}
};
Espero que esto ayude. Esto puede ejecutar de manera efectiva la configuración estática en orden "inverso".
No coloque @BeforeClass
en la clase abstract
. Llamarlo desde cada subclase.
abstract class A {
void doInitialization() {}
}
class B extends A {
@BeforeClass
void doSpecificInitialization() {
super.doInitialization();
}
@Test
void doTests() {}
}
Parece que TestNG tiene @BeforeClass(dependsOnMethods={"doInitialization"})
- pruébalo.
Una forma mejor y más limpia de lograr esto utilizando la herencia puede ser la siguiente:
abstract class A {
@BeforeClass
void doInitialization() {}
}
class B extends A {
@Override
@BeforeClass
void doInitialization() {
super.doInitialization();
}
@Test
void doTests() {}
}
Verifique su declaración de importación. Debería ser
import org.testng.annotations.BeforeClass;
no
import org.junit.BeforeClass;
dependsOnMethod
se puede usar.
por ejemplo, en caso de Spring ( AbstractTestNGSpringContextTests
)
@BeforeClass(alwaysRun = true, dependsOnMethods = "springTestContextPrepareTestInstance")
Para JUnit : Como @fortega ha mencionado: de acuerdo con la API de JUnit: "Los métodos @BeforeClass de las superclases se ejecutarán antes que los de la clase actual".
Pero tenga cuidado de no nombrar ambos métodos con el mismo nombre . Dado que en este caso el padre padre ocultará el método principal. Source
editar: la respuesta a continuación es para JUnit , pero lo dejaré aquí de todos modos, porque podría ser útil.
De acuerdo con la API de JUnit : "Los métodos @BeforeClass de las superclases se ejecutarán antes que los de la clase actual".
Probé esto, y parece funcionar para mí.
Sin embargo, como @Odys menciona a continuación, para JUnit necesita tener los dos métodos denominados de forma diferente, ya que al hacerlo, de lo contrario, solo se ejecutará el método de la subclase porque el padre se sombreará.