@BeforeClass y herencia - orden de ejecución
-
22-09-2019 - |
Pregunta
Tengo una clase base abstracta, que uso como base para mis pruebas unitarias (TestNG 5.10).En esta clase, inicializo todo el entorno para mis pruebas, configuro asignaciones de bases de datos, etc.Esta clase abstracta tiene un método con un @BeforeClass
anotación que realiza la inicialización.
A continuación, extiendo esa clase con clases específicas en las que tengo @Test
métodos y también @BeforeClass
métodos.Estos métodos realizan una inicialización del entorno específica de la clase (p. ej.poner algunos registros en la base de datos).
¿Cómo puedo hacer cumplir una orden específica del @BeforeClass
métodos anotados?Necesito que los de la clase base abstracta se ejecuten antes que los de la clase extensible.
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) // <-/
Solución
No coloque el @BeforeClass
en la clase abstract
. Llamaremos a partir de 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"})
- darle una oportunidad.
Otros consejos
editar:. Respuesta a continuación es para JUnit , pero lo dejaré aquí de todos modos, ya que podría ser útil
De acuerdo con la JUnit API : "El @BeforeClass métodos de superclases se llevará a cabo antes que los de la clase actual ".
He probado esto, y parece que funciona para mí.
Sin embargo, como se menciona a continuación @Odys, por JUnit es necesario tener los dos métodos denominados de forma diferente aunque como hacer lo contrario dará lugar a sólo el método que se está ejecutando subclase porque será ensombrecido el padre.
He añadido public
a la clase abstracta y TestNG (6.0.1) ejecuta el doInitialization () antes de doTests
. TestNG no ejecuta doInitialization()
si quito public
de clase A.
public abstract class A {
@BeforeClass
doInitialization() {...}
}
class B extends A {
@Test
doTests() {...}
}
Me acaba de intentar su ejemplo, con 5.11 y consigo los @BeforeClass de la clase base invocada por primera vez.
Se puede publicar su archivo testng.xml? Tal vez está especificando tanto A como B allí, mientras que sólo el B es necesaria.
No dude en dar seguimiento a la lista de correo de los usuarios TestNG y podemos echar un vistazo más de cerca a su problema.
- Cedric
Me acaba de ir a través de este y encontró una forma más para lograrlo. Sólo tiene que utilizar alwaysRun
en @BeforeClass
o @BeforeMethod
en la clase abstracta, funciona como era de esperar.
public class AbstractTestClass {
@BeforeClass(alwaysRun = true)
public void generalBeforeClass() {
// do stuff
specificBeforeClass();
}
}
Cuando corro de: JUnitCore.runClasses (TestClass.class); Se ejecutará la matriz correctamente, antes de que el niño (No es necesario super.SetUpBeforeClass (); ) Si se ejecuta desde Eclipse: Por alguna razón no se ejecuta la clase base. El trabajo en torno a: Llame a la clase base explícitamente: ( BaseTest.setUpBeforeClass (); ) Es posible que desee tener una bandera en la clase base en caso de que se ejecuta desde una aplicación, para determinar si ya se ha configurado o no. Por lo que sólo se ejecuta una vez si se ejecuta a través de dos métodos posibles (por ejemplo, a partir del eclipse para las pruebas de personal, ya través de la hormiga por un comunicado de acumulación).
Esto parece ser un error con Eclipse, o por lo menos resultados inesperados ..
Para JUnit : Como se ha mencionado @fortega: De acuerdo con la API de JUnit: "Los métodos @BeforeClass de superclases se llevará a cabo antes que los de la clase actual"
Pero tenga cuidado no nombrar los dos métodos con el mismo nombre . Dado que en este caso el método padres se ocultará por el padre del niño. Fuente .
¿Qué hay de tener su método @BeforeClass llamar un método vacío specificBeforeClass () que puede o no puede ser sobrescrito por subclases de esta manera:
public class AbstractTestClass {
@BeforeClass
public void generalBeforeClass() {
// do stuff
specificBeforeClass();
}
protected void specificBeforeClass() {}
}
public class SpecificTest {
@Override
protected void specificBeforeClass() {
// Do specific stuff
}
// Tests
}
dependsOnMethod
se puede utilizar.
por ejemplo. en el caso de la primavera (AbstractTestNGSpringContextTests
)
@BeforeClass(alwaysRun = true, dependsOnMethods = "springTestContextPrepareTestInstance")
Compruebe su declaración de importación. Debe ser
import org.testng.annotations.BeforeClass;
no
import org.junit.BeforeClass;
¿Por qué no intenta crear un método abstracto doSpecialInit () en su super clase, llamada de su método anotado BeforeClass en superclase.
Así que heredan desarrolladores de su clase se ve obligado a poner en práctica este método.
Hay otra solución fácil aquí.
Mi situación particular es que necesito para inyectar servicios de simulacros de "BeforeClass" en la subclase antes "BeforeClass" en el que se ejecuta la superclase.
Para hacer esto -. Sólo tiene que utilizar un @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 se puede ejecutar con eficacia configuración estática en "marcha atrás" orden.
Me he enfrentado a un problema similar en la actualidad, la única diferencia era una clase base abstracta no era
Aquí está mi caso
public class A {
@BeforeClass
private void doInitialization() {...}
}
public class B extends A {
@BeforeClass
private void doSpecificInitialization() {...}
@Test
public void doTests() {...}
}
Se le ocurrió que un método @BeforeClass
de la clase A nunca fue ejecutado.
- A.doInitialization () -> esto nunca se EJECUTADO silencio
- B.doSpecificInitialization ()
- B.doTests ()
Jugando con modificadores de privacidad encontré que TestNG no ejecutará un método anotado @BeforeClass
de clase heredada si un método no es visible desde una clase-heredera
Así que este trabajo:
public class A {
@BeforeClass
private void doInitialization() {...}
}
public class B extends A {
@BeforeClass
//Here a privacy modifier matters -> please make sure your method is public or protected so it will be visible for ancestors
protected void doSpecificInitialization() {...}
@Test
public void doTests() {...}
}
A medida que pasa el siguiente resultado:
- A.doInitialization ()
- B.doSpecificInitialization ()
- B.doTests ()
Esto funciona para mí -
abstract class A {
@BeforeClass
doInitialization() {...}
}
class B extends A {
@Override
@BeforeClass
doInitialization() {
//do class specific init
}
@Test
doTests() {...}
}
En mi caso (JUnit) tengo los mismos métodos llamados setup() en la clase base y en la clase derivada.En este caso solo Se llama al método de la clase derivada y hago que llame al método de la clase base.
A mejor y de manera más limpia para lograr esto utilizando la herencia puede ser de la siguiente manera -
abstract class A {
@BeforeClass
void doInitialization() {}
}
class B extends A {
@Override
@BeforeClass
void doInitialization() {
super.doInitialization();
}
@Test
void doTests() {}
}