JUnit zawsze tworzy jedną instancję klasy testowej dla każdej metody @Test. Jest to podstawowa decyzja projektowa, która ma ułatwić pisanie testów bez skutków ubocznych. Dobre testy nie mają żadnych zależności w kolejności wykonywania (patrz FIRST ), a tworzenie nowych instancji klasy testowej i jej zmiennych instancji dla każdego testu jest kluczowe w osiągnięciu tego. Niektóre platformy testowe wykorzystują tę samą instancję klasy testowej do wszystkich testów, co prowadzi do większej liczby przypadków przypadkowego tworzenia efektów ubocznych między testami.
A ponieważ każda metoda testowa ma swoją własną instancję, nie ma sensu, aby metody @ BeforeClass / @ AfterClass były metodami instancji. W przeciwnym razie, na której instancji klasy testowej należy wywołać metody? Gdyby metody @ BeforeClass / @ AfterClass mogły odwoływać się do zmiennych instancji, to tylko jedna z metod @Test miałaby dostęp do tych samych zmiennych instancji w - reszta miałaby zmienne instancji z wartościami domyślnymi - a @ Metoda testowa byłaby wybierana losowo, ponieważ kolejność metod w pliku .class jest nieokreślona / zależna od kompilatora (IIRC, API odbicia języka Java zwraca metody w tej samej kolejności, w jakiej są zadeklarowane w pliku .class, chociaż również to zachowanie jest nieokreślona - napisałem bibliotekę za faktyczne sortowanie ich według numerów linii).
Zatem wymuszenie statyczności tych metod jest jedynym rozsądnym rozwiązaniem.
Oto przykład:
public class ExampleTest {
@BeforeClass
public static void beforeClass() {
System.out.println("beforeClass");
}
@AfterClass
public static void afterClass() {
System.out.println("afterClass");
}
@Before
public void before() {
System.out.println(this + "\tbefore");
}
@After
public void after() {
System.out.println(this + "\tafter");
}
@Test
public void test1() {
System.out.println(this + "\ttest1");
}
@Test
public void test2() {
System.out.println(this + "\ttest2");
}
@Test
public void test3() {
System.out.println(this + "\ttest3");
}
}
Które wydruki:
beforeClass
ExampleTest@3358fd70 before
ExampleTest@3358fd70 test1
ExampleTest@3358fd70 after
ExampleTest@6293068a before
ExampleTest@6293068a test2
ExampleTest@6293068a after
ExampleTest@22928095 before
ExampleTest@22928095 test3
ExampleTest@22928095 after
afterClass
Jak widać, każdy z testów jest wykonywany z własną instancją. To, co robi JUnit, jest w zasadzie takie samo:
ExampleTest.beforeClass();
ExampleTest t1 = new ExampleTest();
t1.before();
t1.test1();
t1.after();
ExampleTest t2 = new ExampleTest();
t2.before();
t2.test2();
t2.after();
ExampleTest t3 = new ExampleTest();
t3.before();
t3.test3();
t3.after();
ExampleTest.afterClass();
Krótka odpowiedź brzmi: nie ma powodu, aby był statyczny.
W rzeczywistości, uczynienie go statycznym powoduje różnego rodzaju problemy, jeśli używasz Junit do wykonywania testów integracji DAO opartych na DBUnit. Wymaganie statyczne koliduje z wstrzykiwaniem zależności, dostępem do kontekstu aplikacji, obsługą zasobów, rejestrowaniem i wszystkim, co zależy od „getClass”.
źródło
@PostConstruct
do konfigurowania i@AfterClass
niszczenia, a całkowicie ignoruję te statyczne z Junit. Dla testów DAO napisałem następnie własnąTestCaseDataLoader
klasę, którą wywołuję z tych metod.@PostConstruct
i@AfterClass
zachowuje się tak samo jak@Before
i@After
. W rzeczywistości Twoje metody będą wywoływane dla każdej metody testowej, a nie raz dla całej klasy (jak stwierdza Esko Luontola w swojej odpowiedzi, dla każdej metody testowej tworzona jest instancja klasy). Nie widzę użyteczności twojego rozwiązania, więc (chyba że coś mi brakuje)Dokumentacja JUnit wydaje się skromna, ale zgaduję: być może JUnit tworzy nową instancję Twojej klasy testowej przed uruchomieniem każdego przypadku testowego, więc jedynym sposobem na to, aby stan "fixture" był trwały między przebiegami, jest ustawienie statyczne, co może być egzekwowane, upewniając się, że fixtureSetup (metoda @BeforeClass) jest statyczna.
źródło
Chociaż to nie odpowie na pierwotne pytanie. Odpowie na oczywiste dalsze działania. Jak stworzyć regułę działającą przed i po zajęciach oraz przed i po teście.
Aby to osiągnąć, możesz użyć tego wzoru:
Przed (Class) JPAConnection tworzy połączenie po jego zamknięciu (Class).
getEntityManger
zwraca wewnętrzną klasę,JPAConnection
która implementuje EntityManager jpa i może uzyskać dostęp do połączenia wewnątrzjpaConnection
. Przed (test) rozpoczyna transakcję, a po (test) ponownie ją wycofuje.Nie jest to bezpieczne dla wątków, ale można to zrobić.
Wybrany kod
JPAConnection.class
źródło
Wygląda na to, że JUnit tworzy nową instancję klasy testowej dla każdej metody testowej. Wypróbuj ten kod
Wynik to 0 0 0
Oznacza to, że jeśli metoda @BeforeClass nie jest statyczna, to będzie musiała zostać wykonana przed każdą metodą testową i nie będzie możliwości rozróżnienia semantyki @Before i @BeforeClass
źródło
istnieją dwa rodzaje adnotacji:
więc @BeforeClass musi być zadeklarowane jako statyczne, ponieważ jest wywoływane raz. Należy również wziąć pod uwagę, że bycie statycznym jest jedynym sposobem na zapewnienie właściwej propagacji „stanu” między testami (model JUnit nakłada jedną instancję testową na @Test), a ponieważ w Javie tylko metody statyczne mogą uzyskać dostęp do danych statycznych ... @BeforeClass i @ AfterClass można zastosować tylko do metod statycznych.
Ten przykładowy test powinien wyjaśnić @BeforeClass vs @Before use:
wynik:
źródło
Zgodnie z JUnit 5, wydaje się, że filozofia polegająca na ścisłym tworzeniu nowej instancji dla każdej metody testowej została nieco poluzowana. Dodali adnotację, która utworzy instancję klasy testowej tylko raz. W związku z tym ta adnotacja umożliwia również niestatyczne metody z adnotacją @ BeforeAll / @ AfterAll (zamienniki @ BeforeClass / @ AfterClass). Tak więc klasa testowa, taka jak ta:
wydrukowałby:
Tak więc możesz faktycznie tworzyć instancje obiektów raz na klasę testową. Oczywiście oznacza to, że unikanie mutowania obiektów, które są tworzone w ten sposób, jest Twoją odpowiedzialnością.
źródło
Aby rozwiązać ten problem, po prostu zmień metodę
do
i wszystko, co jest zdefiniowane w tej metodzie
static
.źródło