Mam abstrakcyjną klasę bazową, której używam jako bazy dla moich testów jednostkowych (TestNG 5.10). W tej klasie inicjalizuję całe środowisko dla moich testów, konfiguruję mapowania bazy danych itp. Ta abstrakcyjna klasa posiada metodę z @BeforeClass
adnotacją, która wykonuje inicjalizację.
Następnie rozszerzam tę klasę o konkretne klasy, w których mam @Test
metody, a także @BeforeClass
metody. Metody te wykonują specyficzną dla klasy inicjalizację środowiska (np. Umieszczają niektóre rekordy w bazie danych).
Jak mogę wymusić określoną kolejność @BeforeClass
metod z adnotacjami? Potrzebuję, aby te z abstrakcyjnej klasy bazowej były wykonywane przed tymi z klasy rozszerzającej.
Przykład:
abstract class A {
@BeforeClass
doInitialization() {...}
}
class B extends A {
@BeforeClass
doSpecificInitialization() {...}
@Test
doTests() {...}
}
Oczekiwane zamówienie:
A.doInitialization
B.doSpecificInitialization
B.doTests
Rzeczywiste zamówienie:
B.doSpecificInitialization // <- crashes, as the base init is missing
(A.doInitialization // <---not executed
B.doTests) // <-/
źródło
dependsOnMethods
Obejście załatwiło sprawę. Chociaż wolałbym podejście "najpierw superklasy" ...edycja: Odpowiedź poniżej jest dla JUnit , ale i tak ją tutaj zostawię, ponieważ może być pomocna.
Zgodnie z api JUnit : "Metody @BeforeClass nadklas będą uruchamiane przed metodami bieżącej klasy."
Przetestowałem to i wydaje mi się, że działa.
Jednak, jak wspomina @Odys poniżej, dla JUnit musisz mieć dwie metody nazwane inaczej, chociaż inaczej spowoduje to, że uruchomiona zostanie tylko metoda podklasy, ponieważ element nadrzędny zostanie przesłany w cień.
źródło
Dodałem
public
do klasy abstrakcyjnej i TestNG (6.0.1) wykonałem wcześniej doInitialization ()doTests
. TestNG nie wykonuje się,doInitialization()
jeśli usunępublic
z klasy A.public abstract class A { @BeforeClass doInitialization() {...} } class B extends A { @Test doTests() {...} }
źródło
B
również@BeforeClass
metodę z adnotacjami, jak w przypadku OP.Właśnie wypróbowałem twój przykład z 5.11 i otrzymuję @BeforeClass klasy bazowej wywołanej jako pierwsza.
Czy możesz opublikować swój plik testng.xml? Być może określasz tam zarówno A, jak i B, podczas gdy konieczne jest tylko B.
Zapraszam do śledzenia na liście mailingowej testng-users, a my przyjrzymy się bliżej twojemu problemowi.
- Cedric
źródło
Właśnie przez to przeszedłem i znalazłem jeszcze jeden sposób, aby to osiągnąć. Po prostu użyj
alwaysRun
na@BeforeClass
lub@BeforeMethod
w klasie abstrakcyjnej, działa zgodnie z oczekiwaniami.public class AbstractTestClass { @BeforeClass(alwaysRun = true) public void generalBeforeClass() { // do stuff specificBeforeClass(); } }
źródło
Kiedy biegnę z: JUnitCore.runClasses (TestClass.class); Wykona poprawnie rodzica przed dzieckiem (nie potrzebujesz super.SetUpBeforeClass (); ) Jeśli uruchomisz go z Eclipse: Z jakiegoś powodu nie udaje mu się uruchomić klasy bazowej. Sposób obejścia: Wyraźnie wywołaj klasę bazową: ( BaseTest.setUpBeforeClass (); ) Możesz chcieć mieć flagę w klasie bazowej na wypadek, gdybyś uruchomiła ją z aplikacji, aby określić, czy jest już skonfigurowana, czy nie. Więc działa tylko raz, jeśli uruchomisz go za pomocą obu możliwych metod (np. Z eclipse do testów osobistych i przez ANT w przypadku wydania kompilacji).
Wygląda na to, że jest to błąd w Eclipse lub przynajmniej nieoczekiwane wyniki.
źródło
Dla JUnit : Jak wspomniał @fortega: Zgodnie z api JUnit: "Metody @BeforeClass nadklas będą uruchamiane przed metodami bieżącej klasy."
Uważaj jednak, aby nie nazwać obu metod tą samą nazwą . Ponieważ w tym przypadku metoda nadrzędna zostanie ukryta przez rodzica-dziecko. Źródło .
źródło
Co powiesz na wywołanie przez metodę @BeforeClass pustej metody specificBeforeClass (), która może, ale nie musi, zostać nadpisana przez podklasy, takie jak ta:
public class AbstractTestClass { @BeforeClass public void generalBeforeClass() { // do stuff specificBeforeClass(); } protected void specificBeforeClass() {} } public class SpecificTest { @Override protected void specificBeforeClass() { // Do specific stuff } // Tests }
źródło
dependsOnMethod
może być użyte.np. w przypadku wiosny (
AbstractTestNGSpringContextTests
)@BeforeClass(alwaysRun = true, dependsOnMethods = "springTestContextPrepareTestInstance")
źródło
Sprawdź wyciąg z importu. Powinno być
import org.testng.annotations.BeforeClass;
nie
import org.junit.BeforeClass;
źródło
To działa dla mnie -
abstract class A { @BeforeClass doInitialization() {...} } class B extends A { @Override @BeforeClass doInitialization() { //do class specific init } @Test doTests() {...} }
źródło
Dlaczego nie spróbujesz utworzyć abstrakcyjnej metody doSpecialInit () w swojej superklasie, wywoływanej z Twojej metody z adnotacjami BeforeClass w nadklasie.
Dlatego programiści dziedziczący twoją klasę są zmuszeni do implementacji tej metody.
źródło
Jest tu inne proste rozwiązanie.
Moja szczególna sytuacja polega na tym, że muszę wstrzyknąć usługi pozorowane z klasy „BeforeClass” w podklasie przed wykonaniem elementu „BeforeClass” w nadklasie.
Aby to zrobić - po prostu użyj
@ClassRule
w podklasie.Na przykład:
@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 } };
Mam nadzieję, że to pomoże. Może to skutecznie wykonać statyczną konfigurację w „odwrotnej” kolejności.
źródło
Dzisiaj miałem podobny problem, jedyną różnicą było to, że klasa bazowa nie była abstrakcyjna
Oto moja sprawa
public class A { @BeforeClass private void doInitialization() {...} } public class B extends A { @BeforeClass private void doSpecificInitialization() {...} @Test public void doTests() {...} }
Okazało się, że
@BeforeClass
metoda z klasy A nigdy nie została wykonana.Gry z modyfikatorów prywatności stwierdziliśmy, że TestNG nie wykona się
@BeforeClass
uwagami z odziedziczonej metody klasy , jeśli metoda nie jest widoczny z klasy-spadkobiercaWięc to zadziała:
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() {...} }
W rezultacie następuje:
źródło
W moim przypadku (JUnit) mam te same metody o nazwie setup () w klasie bazowej i klasie pochodnej. W tym przypadku tylko metoda klasy pochodnej nazywa, i mam go wywołać metodę klasy bazowej.
źródło
Lepszym i czystszym sposobem osiągnięcia tego za pomocą dziedziczenia może być:
abstract class A { @BeforeClass void doInitialization() {} } class B extends A { @Override @BeforeClass void doInitialization() { super.doInitialization(); } @Test void doTests() {} }
źródło