@BeforeClass and inheritance – orden de ejecución

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 esperada:

 A.doInitialization B.doSpecificInitialization B.doTests 

Orden actual:

 B.doSpecificInitialization // <- crashes, as the base init is missing (A.doInitialization // <---not executed B.doTests) // <-/ 

No ponga la @BeforeClass en la clase abstract . Llámalo 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"}) : inténtalo.

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á.

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 usted está especificando tanto A como 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

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 manera más de lograrlo. 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(); } } 

¿Qué tal si tu método @BeforeClass llama a un método specificBeforeClass () vacío que puede ser o no sobrescrito por subclases como esta?

 public class AbstractTestClass { @BeforeClass public void generalBeforeClass() { // do stuff specificBeforeClass(); } protected void specificBeforeClass() {} } public class SpecificTest { @Override protected void specificBeforeClass() { // Do specific stuff } // Tests } 

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 comstackción).

Esto parece ser un error con Eclipse, o al menos resultados inesperados.

Para JUnit : Como @fortega ha mencionado: Según la api JUnit: “Los métodos de superclases @BeforeClass 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 método padre estará oculto por el padre hijo. Fuente

dependsOnMethod puede ser utilizado.

por ejemplo, en el caso de Spring ( AbstractTestNGSpringContextTests )

 @BeforeClass(alwaysRun = true, dependsOnMethods = "springTestContextPrepareTestInstance") 

Verifique su statement de importación. Debería ser

import org.testng.annotations.BeforeClass;

no

import org.junit.BeforeClass;

¿Por qué no intentas crear un método abstracto doSpecialInit () en tu súper clase, llamado desde tu método anotado BeforeClass en superclase?

Así que los desarrolladores que heredan su clase se ven obligados a implementar este método.

Hay otra solución fácil aquí.

Mi situación particular es que necesito inyectar servicios simulados de “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 efectivamente la configuración estática en orden “inverso”.

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.

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() {} }