@BeforeClass ed ereditarietà: ordine di esecuzione
-
22-09-2019 - |
Domanda
Ho una classe base astratta, che utilizzo come base per i miei test unitari (TestNG 5.10).In questa classe inizializzo l'intero ambiente per i miei test, impostando le mappature dei database, ecc.Questa classe astratta ha un metodo con a @BeforeClass
annotazione che esegue l'inizializzazione.
Successivamente, estendo quella classe con classi specifiche in cui ho @Test
metodi e anche @BeforeClass
metodi.Questi metodi eseguono l'inizializzazione specifica della classe dell'ambiente (ad es.inserire alcuni record nel database).
Come posso far rispettare un ordine specifico del @BeforeClass
metodi annotati?Ho bisogno che quelli della classe base astratta vengano eseguiti prima di quelli della classe estesa.
Esempio:
abstract class A {
@BeforeClass
doInitialization() {...}
}
class B extends A {
@BeforeClass
doSpecificInitialization() {...}
@Test
doTests() {...}
}
Ordine previsto:
A.doInitialization
B.doSpecificInitialization
B.doTests
Ordine effettivo:
B.doSpecificInitialization // <- crashes, as the base init is missing
(A.doInitialization // <---not executed
B.doTests) // <-/
Soluzione
Non mettere il @BeforeClass
sulla classe abstract
. Chiamare da ogni sottoclasse.
abstract class A {
void doInitialization() {}
}
class B extends A {
@BeforeClass
void doSpecificInitialization() {
super.doInitialization();
}
@Test
void doTests() {}
}
Sembra TestNG ha @BeforeClass(dependsOnMethods={"doInitialization"})
- fare un tentativo.
Altri suggerimenti
modifica:. Risposta di seguito è per JUnit , ma lascio qui in ogni caso, perché potrebbe essere utile
Secondo il JUnit api : "I @BeforeClass metodi di superclassi verranno eseguiti prima di quelli della classe corrente ".
Ho provato questo, e sembra funzionare per me.
Tuttavia, come @Odys cita di seguito, per JUnit è necessario avere due metodi chiamati in modo diverso anche se, come fare altrimenti comporterà solo il metodo della sottoclasse in esecuzione perché il genitore sarà oscurato.
Ho aggiunto public
alla classe astratta e TestNG (6.0.1) eseguito il doInitialization () prima doTests
. TestNG non esegue doInitialization()
se tolgo public
dalla classe A.
public abstract class A {
@BeforeClass
doInitialization() {...}
}
class B extends A {
@Test
doTests() {...}
}
Ho appena provato il tuo esempio con 5.11 e ottengo il @BeforeClass della classe base invocato prima.
È possibile inviare il file testng.xml? Forse si sta specificando sia A che B lì, mentre solo B è necessaria.
Non esitate a seguito alle TestNG-users mailing-list e siamo in grado di dare uno sguardo più da vicino il problema.
- Cedric
Ho appena passato attraverso questo e ha trovato un altro modo per raggiungere questo obiettivo. Basta usare alwaysRun
su @BeforeClass
o @BeforeMethod
nella classe astratta, funziona come ci si aspetterebbe.
public class AbstractTestClass {
@BeforeClass(alwaysRun = true)
public void generalBeforeClass() {
// do stuff
specificBeforeClass();
}
}
Quando eseguo da: JUnitCore.runClasses (TestClass.class); Si eseguirà il genitore correttamente, prima che il bambino (non è necessario super.SetUpBeforeClass (); ) Se lo si esegue da Eclipse: Per qualche ragione non riesce a eseguire la classe di base. Il lavoro intorno: Chiamare la classe base esplicitamente: ( BaseTest.setUpBeforeClass (); ) Si consiglia di avere una bandiera nella classe base nel caso in cui lo si esegue da un'applicazione, per determinare se è già messa a punto o meno. Quindi viene eseguito solo una volta, se lo si esegue tramite due metodi possibili (ad esempio da Eclipse per la prova personale, e attraverso ANT per un rilascio build).
Questo sembra essere un bug con Eclipse, o risultati almeno imprevisti ..
Per JUnit : Come @fortega ha detto: Secondo l'api JUnit: "I metodi di @BeforeClass superclassi verranno eseguiti prima di quelli della classe corrente"
Ma attenzione a non fare il nome entrambi i metodi con lo stesso nome . Dal momento che in questo caso il metodo di genitore sarà nascosto dai genitori del bambino. Source.
Che ne dite di avere il vostro metodo di @BeforeClass chiamare un metodo vuoto specificBeforeClass (), che può o non può essere sovrascritto da classi secondarie in questo modo:
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
può essere utilizzato.
es. in caso di primavera (AbstractTestNGSpringContextTests
)
@BeforeClass(alwaysRun = true, dependsOnMethods = "springTestContextPrepareTestInstance")
Controlla la tua istruzione import. Dovrebbe essere
import org.testng.annotations.BeforeClass;
non
import org.junit.BeforeClass;
Perché non si tenta di creare un metodo astratto doSpecialInit () nella classe super, chiamare dal proprio BeforeClass metodo annotato nella superclasse.
Quindi sviluppatori ereditare la classe è costretto a implementare questo metodo.
C'è un'altra soluzione facile qui.
La mia situazione particolare, è che ho bisogno di iniettare servizi finto da "BeforeClass" nella sottoclasse prima "BeforeClass" in viene eseguita la superclasse.
Per fare questo - è sufficiente utilizzare un @ClassRule
nella sottoclasse
Ad esempio:
@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
}
};
Spero che questo aiuta. Questo può eseguire in modo efficace impostazione statica in modo "inverso".
Ho affrontato un problema simile oggi, l'unica differenza era che la classe Base non era astratta
Ecco il mio caso
public class A {
@BeforeClass
private void doInitialization() {...}
}
public class B extends A {
@BeforeClass
private void doSpecificInitialization() {...}
@Test
public void doTests() {...}
}
È avvenuto che a @BeforeClass
il metodo della classe A non è mai stato eseguito.
- A.doInitialization() -> QUESTO NON È MAI STATO ESEGUITO in silenzio
- B.doSpecificInitialization()
- B.doTest()
Giocando con i modificatori della privacy ho scoperto che TestNG non verrà eseguito UN @BeforeClass
metodo annotato dalla classe ereditata se un metodo non è visibile da un erede di classe
Quindi funzionerà:
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() {...}
}
Di conseguenza accade quanto segue:
- A.doInizializzazione()
- B.doSpecificInitialization()
- B.doTest()
Questo funziona per me -
abstract class A {
@BeforeClass
doInitialization() {...}
}
class B extends A {
@Override
@BeforeClass
doInitialization() {
//do class specific init
}
@Test
doTests() {...}
}
Nel mio caso (JUnit) ho gli stessi metodi chiamati setup () nella classe base e la classe derivata. In questo caso, solo il metodo della classe derivata si chiama, e ce l'ho chiamare il metodo della classe base.
Un modo migliore e più pulito per raggiungere questo obiettivo utilizzando l'ereditarietà può essere come segue -
abstract class A {
@BeforeClass
void doInitialization() {}
}
class B extends A {
@Override
@BeforeClass
void doInitialization() {
super.doInitialization();
}
@Test
void doTests() {}
}