Próbuję przeprowadzić konfigurację i porzucić zestaw testów integracyjnych, używając jUnit 4.4 do wykonania testów. Rozerwanie musi przebiegać niezawodnie. Mam inne problemy z TestNG, więc szukam przeniesienia z powrotem do jUnit. Jakie punkty zaczepienia są dostępne do wykonania przed uruchomieniem jakichkolwiek testów i po zakończeniu wszystkich testów?
Uwaga: używamy maven 2 do naszej kompilacji. Próbowałem używać faz pre-
& maven post-integration-test
, ale jeśli test się nie powiedzie, maven zatrzymuje się i nie działa post-integration-test
, co nie pomaga.
java
testing
junit
integration-testing
sblundy
źródło
źródło
post-integration-test
jeśli test się nie powiedzie. Zobacz także tę stronę wiki .Odpowiedzi:
Tak, możliwe jest niezawodne uruchamianie metod konfiguracji i usuwania metod przed i po testach w zestawie testów. Pokażę w kodzie:
package com.test; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) @SuiteClasses({Test1.class, Test2.class}) public class TestSuite { @BeforeClass public static void setUp() { System.out.println("setting up"); } @AfterClass public static void tearDown() { System.out.println("tearing down"); } }
Twoja
Test1
klasa wyglądałaby mniej więcej tak:package com.test; import org.junit.Test; public class Test1 { @Test public void test1() { System.out.println("test1"); } }
... i możesz sobie wyobrazić, że
Test2
wygląda podobnie. Gdybyś biegałTestSuite
, dostałbyś:Możesz więc zobaczyć, że konfiguracja / zrywanie działa tylko odpowiednio przed i po wszystkich testach.
Haczyk: działa to tylko wtedy, gdy uruchamiasz zestaw testów i nie uruchamiasz Test1 i Test2 jako oddzielnych testów JUnit. Wspomniałeś, że używasz mavena, a wtyczka Maven surefire lubi uruchamiać testy indywidualnie, a nie jako część pakietu. W tym przypadku zalecałbym utworzenie nadklasy, którą rozszerza każda klasa testowa. Nadklasa zawiera następnie metody @BeforeClass i @AfterClass z adnotacjami. Chociaż nie jest tak czysta jak powyższa metoda, myślę, że będzie działać dla Ciebie.
Jeśli chodzi o problem z nieudanymi testami, możesz ustawić maven.test.error.ignore tak, aby kompilacja była kontynuowana po nieudanych testach. Nie jest to zalecane jako ciągła praktyka, ale powinno zapewnić ci funkcjonowanie, dopóki wszystkie testy nie przejdą. Więcej szczegółów można znaleźć w dokumentacji Maven surefire .
źródło
Mój kolega zasugerował, co następuje: możesz użyć niestandardowego RunListener i zaimplementować metodę testRunFinished (): http://junit.sourceforge.net/javadoc/org/junit/runner/notification/RunListener.html#testRunFinished(org. junit.runner.Result)
Aby zarejestrować RunListener, po prostu skonfiguruj pewną wtyczkę w następujący sposób: http://maven.apache.org/surefire/maven-surefire-plugin/examples/junit.html sekcja „Korzystanie z niestandardowych nasłuchiwaczy i reporterów”
Ta konfiguracja powinna również zostać wybrana przez bezpieczną wtyczkę. To rozwiązanie jest świetne, ponieważ nie musisz określać pakietów, wyszukiwać klas testowych ani nic z tego - pozwala Mavenowi wykonać swoją magię, czekając na zakończenie wszystkich testów.
źródło
Możesz użyć adnotacji @ClassRule w JUnit 4.9+, jak opisałem w odpowiedzi na inne pytanie .
źródło
Używając adnotacji, możesz zrobić coś takiego:
import org.junit.*; import static org.junit.Assert.*; import java.util.*; class SomethingUnitTest { @BeforeClass public static void runBeforeClass() { } @AfterClass public static void runAfterClass() { } @Before public void setUp() { } @After public void tearDown() { } @Test public void testSomethingOrOther() { } }
źródło
Tutaj my
źródło
Jeśli chodzi o „Uwaga: używamy maven 2 do naszej kompilacji. Próbowałem użyć faz testów maven przed i po integracji, ale jeśli test się nie powiedzie, maven zatrzymuje się i nie uruchamia testu po integracji co nie jest pomocne ”.
zamiast tego możesz wypróbować wtyczkę failafe-plugin, myślę, że ma ona funkcję zapewniającą czyszczenie niezależnie od konfiguracji lub statusu etapu pośredniego
źródło
Zakładając, że wszystkie Twoje testy mogą rozszerzać klasę „techniczną” i znajdują się w tym samym pakiecie, możesz zrobić małą sztuczkę:
public class AbstractTest { private static int nbTests = listClassesIn(<package>).size(); private static int curTest = 0; @BeforeClass public static void incCurTest() { curTest++; } @AfterClass public static void closeTestSuite() { if (curTest == nbTests) { /*cleaning*/ } } } public class Test1 extends AbstractTest { @Test public void check() {} } public class Test2 extends AbstractTest { @Test public void check() {} }
Pamiętaj, że to rozwiązanie ma wiele wad:
Więcej informacji: listClassesIn () => Jak znaleźć wszystkie podklasy danej klasy w Javie?
źródło
O ile wiem, nie ma takiego mechanizmu w JUnit, jednak można spróbować podklasy Suite i nadpisać metodę run () wersją, która zapewnia podpięcia.
źródło
Ponieważ maven-surefire-plugin nie uruchamia najpierw klasy Suite, ale traktuje klasy Suite i testowe tak samo, więc możemy skonfigurować wtyczkę jak poniżej, aby włączyć tylko klasy z pakietu i wyłączyć wszystkie testy. Suite uruchomi wszystkie testy.
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.5</version> <configuration> <includes> <include>**/*Suite.java</include> </includes> <excludes> <exclude>**/*Test.java</exclude> <exclude>**/*Tests.java</exclude> </excludes> </configuration> </plugin>
źródło
Myślę, że jedynym sposobem uzyskania pożądanej funkcjonalności byłoby zrobienie czegoś takiego
import junit.framework.Test; import junit.framework.TestResult; import junit.framework.TestSuite; public class AllTests { public static Test suite() { TestSuite suite = new TestSuite("TestEverything"); //$JUnit-BEGIN$ suite.addTestSuite(TestOne.class); suite.addTestSuite(TestTwo.class); suite.addTestSuite(TestThree.class); //$JUnit-END$ } public static void main(String[] args) { AllTests test = new AllTests(); Test testCase = test.suite(); TestResult result = new TestResult(); setUp(); testCase.run(result); tearDown(); } public void setUp() {} public void tearDown() {} }
Używam czegoś takiego w Eclipse, więc nie jestem pewien, jak przenośny jest poza tym środowiskiem
źródło
Jeśli nie chcesz tworzyć zestawu i musisz wymieniać wszystkie swoje klasy testowe, możesz użyć refleksji, aby znaleźć liczbę klas testowych dynamicznie i odliczać w dół w klasie bazowej @AfterClass, aby wykonać tearDown tylko raz:
public class BaseTestClass { private static int testClassToRun = 0; // Counting the classes to run so that we can do the tear down only once static { try { Field field = ClassLoader.class.getDeclaredField("classes"); field.setAccessible(true); @SuppressWarnings({ "unchecked", "rawtypes" }) Vector<Class> classes = (Vector<Class>) field.get(BlockJUnit4ClassRunner.class.getClassLoader()); for (Class<?> clazz : classes) { if (clazz.getName().endsWith("Test")) { testClassToRun++; } } } catch (Exception ignore) { } } // Setup that needs to be done only once static { // one time set up } @AfterClass public static void baseTearDown() throws Exception { if (--testClassToRun == 0) { // one time clean up } } }
Jeśli wolisz używać @BeforeClass zamiast bloków statycznych, możesz również użyć flagi boolowskiej, aby wykonać liczenie odbić i przetestować konfigurację tylko raz przy pierwszym wywołaniu. Mam nadzieję, że to komuś pomoże, zajęło mi całe popołudnie, aby wymyślić lepszy sposób niż wyliczenie wszystkich klas w zestawie.
Teraz wszystko, co musisz zrobić, to rozszerzyć tę klasę na wszystkie klasy testowe. Mieliśmy już klasę bazową, która zapewniała kilka wspólnych elementów dla wszystkich naszych testów, więc było to dla nas najlepsze rozwiązanie.
Inspiracja pochodzi z tej odpowiedzi SO https://stackoverflow.com/a/37488620/5930242
Jeśli nie chcesz rozszerzać tej klasy wszędzie, ta ostatnia odpowiedź SO może zrobić, co chcesz.
źródło