Warunkowe ignorowanie testów w JUnit 4

365

OK, więc @Ignoreadnotacja jest dobra do oznaczenia, że ​​przypadek testowy nie powinien zostać uruchomiony.

Czasami jednak chcę zignorować test oparty na informacjach wykonawczych. Przykładem może być test współbieżności, który należy uruchomić na maszynie z określoną liczbą rdzeni. Jeśli ten test zostałby uruchomiony na maszynie jednoprocesorowej, nie sądzę, że poprawne byłoby po prostu zdanie testu (ponieważ nie został on uruchomiony), a na pewno nie byłoby poprawne zdanie testu i przerwanie kompilacji .

Chcę więc móc ignorować testy w czasie wykonywania, ponieważ wydaje się to właściwym wynikiem (ponieważ środowisko testowe pozwoli kompilacji przejść, ale zapisz, że testy nie zostały uruchomione). Jestem całkiem pewien, że adnotacja nie zapewni mi tej elastyczności i podejrzewam, że będę musiał ręcznie utworzyć pakiet testowy dla danej klasy. Jednak dokumentacja nie wspomina nic na ten temat, a przeglądając interfejs API, nie jest również jasne, w jaki sposób można to zrobić programowo (tj. Jak programowo utworzyć instancję Testlub podobną, która jest równoważna z instancją utworzoną przez @Ignoreadnotację?).

Jeśli ktoś zrobił coś podobnego w przeszłości lub ma jasne pojęcie, jak inaczej mógłbym się tym zająć, chętnie o tym usłyszę.

Andrzej Doyle
źródło

Odpowiedzi:

476

JUnit to zrobić w czasie wykonywania org.junit.Assume.

 @Before
 public void beforeMethod() {
     org.junit.Assume.assumeTrue(someCondition());
     // rest of setup.
 }

Możesz to zrobić w @Beforemetodzie lub w samym teście, ale nie w @Aftermetodzie. Jeśli zrobisz to w samym teście, twoja @Beforemetoda zostanie uruchomiona. Możesz to również zrobić wewnątrz, @BeforeClassaby zapobiec inicjalizacji klasy.

Niepowodzenie założenia powoduje, że test jest ignorowany.

Edycja: Aby porównać z @RunIfadnotacją z junit-ext , ich przykładowy kod wyglądałby następująco:

@Test
public void calculateTotalSalary() {
    assumeThat(Database.connect(), is(notNull()));
    //test code below.
}

Nie wspominając o tym, że o wiele łatwiej jest przechwycić i użyć połączenia z Database.connect()metody w ten sposób.

Yishai
źródło
1
@notnoop, to wcale nie jest moja obserwacja. Są ignorowane. Runner testowy IDEA zgłasza je w ten sposób, a spojrzenie na kod źródłowy JUnit pokazuje, że zgłasza test jako zignorowany.
Yishai,
1
Cytując: „W przyszłości może się to zmienić, a błędne założenie może doprowadzić do zignorowania testu”. W rzeczywistości zmieniło się, jak sądzę od 4.5. Obecny javadoc mówi: „Domyślny moduł uruchamiający JUnit traktuje testy z błędnymi założeniami jako ignorowane. Niestandardowe elementy uruchamiające mogą zachowywać się inaczej”. github.com/KentBeck/junit/blob/…
Yishai
4
Eclipse 3.6 z Junit 4.8.1 zgłasza fałszywe założenia jako pozytywny test. To samo z mrówką 1.8.1.
fijiaaron,
8
To, że Eclipse zgłasza błędne
Martin
1
@JeffStorey, to szukasz kilku rzeczy. Jednym z nich jest @BeforeClassadnotacja, w której może się nie powieść założenie, które pominie całą klasę. Innym jest @ClassRule(dla drobnoziarnistej kontroli, ale jednorazowo dla całej klasy).
Yishai
51

Powinieneś sprawdzić Junit-extprojekt. Mają RunIfadnotację, która wykonuje testy warunkowe, takie jak:

@Test
@RunIf(DatabaseIsConnected.class)
public void calculateTotalSalary() {
    //your code there
}

class DatabaseIsConnected implements Checker {
   public boolean satisify() {
        return Database.connect() != null;
   }
}

[Próbka kodu pobrana z samouczka]

notnoop
źródło
3
Dziękuję za tę odpowiedź - interesującą alternatywną składnię dla funkcjonalności, ale pójdę z nią Assumebezpośrednio, aby nie wprowadzać innej zależności.
Andrzej Doyle
3
Ja osobiście wolę to rozwiązanie. Jeśli masz wiele testów, które powinny być uruchamiane w tych samych warunkach, byłoby to o wiele bardziej idealne niż używanie opcji Zakładaj w każdym teście. Ponadto, jeśli można tego użyć na poziomie klasy, a nie na poziomie metody, będzie to jeszcze bardziej idealne.
Richard
Wolałbym to, ponieważ pomaga to uruchomić test warunkowo w czasie wykonywania. Jest odpowiedni, gdy zostanie przeprowadzonych kilka testów jednostkowych, a warunkiem jest przeprowadzenie testów jednostkowych na konkretnym kontrolerze. Naprawdę zadziwiło mnie, że junit-ext nie jest dostępny w repozytorium maven. Jak moglibyśmy skorzystać z tego projektu maven.
shambhu
4
Adnotacja jak @RunIfoddziela warunek, w którym test powinien zostać uruchomiony od rzeczywistego kodu testu, co moim zdaniem jest dobre. Nie podoba mi się to, że wymaga konkretnego testera. Dlatego napisałem regułę JUnit, aby warunkowo ignorować testy.
Rüdiger Herrmann
2
Po zainstalowaniu słoika junit-ext (znajdującego się tutaj code.google.com/p/junit-ext/downloads/… ) w naszym lokalnym repozytorium i wdrożeniu adnotacji @RunIf ... nic! Jest to całkowicie ignorowane i myślę, że powodem może być to, że junit-ext wydaje się zależeć od junit 4.5. Potrzebujemy 4.9+ ze względu na wiosenny test. Więc ... nieważne.
Marc
7

W JUnit 4 inną opcją może być utworzenie adnotacji oznaczającej, że test musi spełniać Twoje niestandardowe kryteria, a następnie rozszerzenie domyślnego elementu uruchamiającego o własne i użycie refleksji, opierając swoją decyzję na niestandardowych kryteriach. Może to wyglądać mniej więcej tak:

public class CustomRunner extends BlockJUnit4ClassRunner {
    public CTRunner(Class<?> klass) throws initializationError {
        super(klass);
    }

    @Override
    protected boolean isIgnored(FrameworkMethod child) {
        if(shouldIgnore()) {
            return true;
        }
        return super.isIgnored(child);
    }

    private boolean shouldIgnore(class) {
        /* some custom criteria */
    }
}
Kyle Shrader
źródło
Chociaż wygląda to ładnie i czysto, nie działa z aktualnymi wersjami JUnit4, ponieważ BlockJUnit4ClassRunnernie oferuje isIgnoredjuż tej metody.
Dave
-2

Szybka uwaga: Assume.assumeTrue(condition)ignoruje pozostałe kroki, ale pozytywnie przechodzi test. Aby zakończyć test niepowodzeniem, użyj org.junit.Assert.fail()instrukcji warunkowej. Działa tak samo, Assume.assumeTrue()ale nie przejdzie testu.

TIN TIN
źródło
5
Jak zauważono w odpowiedziach powyżej, błędne założenie nie powoduje przejścia testu, zwraca osobny status. Niektórzy biegacze mogą błędnie zgłosić to tak, jakby to było zaliczenie, ale jest to słabość / błąd w testowym programie uruchamiającym (a domyślny program uruchamiający JUnit wyświetla test jako ignorowany). A jeśli chodzi o twoje ostatnie zdanie, zaliczenie testu nie jest dokładnie tym, co chcę (red.) Zrobić.
Andrzej Doyle,
Oh ok Testy przeszły w moim przypadku nieudane założenie, ale chciałem, aby zostały zgłoszone jako nieudane (szukałem wyjątku od Test Watchera). Wymuszenie niepowodzenia pomogło mi.
TIN TIN