JUnit4 fail () jest tutaj, ale gdzie jest pass ()?

85

W fail()bibliotece JUnit4 jest metoda. Podoba mi się, ale doświadczam braku pass()metody, której nie ma w bibliotece. Dlaczego tak się dzieje?

Odkryłem, że mogę użyć assertTrue(true)zamiast tego, ale nadal wygląda to nielogicznie.

@Test
 public void testSetterForeignWord(){
  try {
   card.setForeignWord("");
   fail();
  } catch (IncorrectArgumentForSetter ex){
  }

 // assertTrue(true);
 }
Eugene
źródło
7
Po prostu użyj instrukcji return - w większości przypadków zostanie ona przekazana jako pass ().
topchef
@topchef ten pojedynczy komentarz uderzył młotkiem w głowę, podczas gdy wszyscy inni debatują o tym, który jest akceptowalny, a który nie.
Niektóre systemy testowe (perl Test :: Simple) zliczają potwierdzenia i nie powiodły się. Junit liczy jednak liczbę metod testowych, które kończą się pomyślnie i kończą się niepowodzeniem. Zatem Junit nie ma takiego samego zastosowania dla passmetody.
Randall Whitman

Odpowiedzi:

65

Dopóki test nie zgłosi wyjątku, przechodzi, chyba że twoja @Testadnotacja określa oczekiwany wyjątek. Przypuszczam, że pass()można by rzucić specjalny wyjątek, który JUnit zawsze interpretuje jako pozytywny, aby zewrzeć test, ale byłoby to sprzeczne ze zwykłym projektowaniem testów (tj. Zakładałoby sukces i kończyło się niepowodzeniem tylko wtedy, gdy asercja nie powiedzie się) i jeśli ludzie otrzymają pomysł pass(), który byłby preferowany , znacznie spowolniłby duży zestaw testów zaliczających (ze względu na narzut tworzenia wyjątków). Niepowodzenie testów nie powinno być normą, więc nie jest to wielka sprawa, jeśli mają taki narzut.

Zauważ, że twój przykład może zostać przepisany w ten sposób:

@Test(expected=IncorrectArgumentForSetter.class)
public void testSetterForeignWord("") throws Exception {
  card.setForeignWord("");
}

Powinieneś także preferować używanie standardowych wyjątków Java. Twój IncorrectArgumentForSetterprawdopodobnie powinien być IllegalArgumentException.

ColinD
źródło
4
Metoda fail () i metody assertX () po prostu generują błąd AssertionError, który powoduje nieczyste zakończenie metody testowej. Dlatego udany powrót oznacza sukces ...
Steven Schlansker
-1 - metoda pass () nic nie robi - kończy test natychmiast, bez wyjątków. W większości przypadków byłoby to równoważne z instrukcją return (z wyjątkiem oczekiwanych wyjątków, limitów czasu itp.).
topchef
1
@grigory: Masz rację, że pass()metoda nie mogła po prostu nic nie zrobić, aby test nie mógł się nie powieść po jej wywołaniu. Więc usunąłem to zdanie.
ColinD,
Nie mogę ci wystarczająco podziękować, pomogło mi wyjść z wielu frustracji!
N00b Pr0grammer
71

Call returnoświadczenie za każdym razem, gdy test zostanie zakończony i zdany.

Horkruks7
źródło
3
+1 musiało być poprawną odpowiedzią (w większości przypadków z wyjątkiem oczekiwanych, limitów czasu itp.)
topchef
Wydaje się rzeczywiście najprostszym i najbardziej użytecznym sposobem na zakończenie testu.
Benj
7

Myślę, że to pytanie wymaga zaktualizowanej odpowiedzi, ponieważ większość odpowiedzi tutaj jest dość nieaktualna.

Po pierwsze, na pytanie PO:

Myślę, że całkiem dobrze przyjęto, że wprowadzenie koncepcji „oczekiwanego wyjątku” do JUnit było złym posunięciem, ponieważ ten wyjątek można zgłosić w dowolnym miejscu i zda on test. Działa, jeśli wyrzucasz (i potwierdzasz) wyjątki specyficzne dla domeny, ale tego typu wyjątki rzucam tylko wtedy, gdy pracuję nad kodem, który musi być absolutnie nieskazitelny, - większość APIS po prostu wyrzuci wbudowane wyjątki, takie jak IllegalArgumentExceptionlub IllegalStateException. Jeśli dwa wywołania, które wykonujesz, mogą potencjalnie spowodować te wyjątki, to@ExpectedException adnotacja zielony pasek twojego testu, nawet jeśli jest to zła linia, która zgłasza wyjątek!

W tej sytuacji napisałem zajęcia, które na pewno napisało wielu innych, to jest assertThrowsmetoda:

public class Exceptions {
    private Exceptions(){}

    public static void assertThrows(Class<? extends Exception> expectedException, Runnable actionThatShouldThrow){
        try{
            actionThatShouldThrow.run();
            fail("expected action to throw " + expectedException.getSimpleName() + " but it did not.");
        }
        catch(Exception e){
            if ( ! expectedException.isInstance(e)) {
                throw e;
            }
        }
    }
}

ta metoda po prostu zwraca, jeśli wyjątek zostanie zgłoszony, umożliwiając wykonanie dalszych asercji / weryfikacji w teście.

dzięki składni java 8 twój test wygląda naprawdę ładnie. Poniżej znajduje się jeden z prostszych testów na naszym modelu wykorzystującym metodę:

@Test
public void when_input_lower_bound_is_greater_than_upper_bound_axis_should_throw_illegal_arg() {
    //setup
    AxisRange range = new AxisRange(0,100);

    //act
    Runnable act = () -> range.setLowerBound(200);

    //assert
    assertThrows(IllegalArgumentException.class, act);
}

testy te są trochę dziwne, ponieważ krok „działaj” w rzeczywistości nie wykonuje żadnej czynności, ale myślę, że znaczenie jest nadal dość jasne.

na maven jest też mała biblioteka o nazwie catch -ception, która używa składni w stylu mockito, aby sprawdzić, czy wyjątki są generowane. Wygląda ładnie, ale nie jestem fanem dynamicznych proxy. To powiedziawszy, składnia jest tak zręczna, że ​​pozostaje kusząca:

// given: an empty list
List myList = new ArrayList();

// when: we try to get the first element of the list
// then: catch the exception if any is thrown 
catchException(myList).get(1);

// then: we expect an IndexOutOfBoundsException
assert caughtException() instanceof IndexOutOfBoundsException;

Na koniec, w sytuacji, w której znalazłem się, aby dostać się do tego wątku, istnieje sposób na zignorowanie testów, jeśli zostanie spełniony jakiś warunek.

W tej chwili pracuję nad uzyskaniem niektórych bibliotek DLL wywoływanych przez bibliotekę java natywną ładującą bibliotekę o nazwie JNA, ale nasz serwer kompilacji jest w systemie Ubuntu. Lubię próbować napędzać ten rodzaj rozwoju za pomocą testów JUnit - chociaż w tym momencie są one dalekie od „jednostek” -. Chcę przeprowadzić test, jeśli jestem na komputerze lokalnym, ale zignorować test, jeśli jesteśmy na Ubuntu. JUnit 4 ma na to przepis, zwany Assume:

@Test
public void when_asking_JNA_to_load_a_dll() throws URISyntaxException {
    //this line will cause the test to be branded as "ignored" when "isCircleCI" 
    //(the machine running ubuntu is running this test) is true.
    Assume.assumeFalse(BootstrappingUtilities.isCircleCI());
    //an ignored test will typically result in some qualifier being put on the results, 
    //but will also not typically prevent a green-ton most platforms. 

    //setup
    URL url = DLLTestFixture.class.getResource("USERDLL.dll");
    String path = url.toURI().getPath();
    path = path.substring(0, path.lastIndexOf("/"));

    //act
    NativeLibrary.addSearchPath("USERDLL", path);
    Object dll = Native.loadLibrary("USERDLL", NativeCallbacks.EmptyInterface.class);

    //assert
    assertThat(dll).isNotNull();
}
Groostav
źródło
Jak powiedziałeś, „działanie” nie robi nic konkretnego, więc nadal nie wiemy, co dokładnie zgłasza wyjątek, czy jest to linia, której się spodziewamy, czy nie. W tym przypadku przykład jest dość prosty do przetestowania i zweryfikowania, ale wyobraź sobie, że Twój test zawiera metodę Utility, która używa zagnieżdżonych metod przed zwróceniem wyniku. Nadal nie ma sposobu, aby uzyskać źródło problemu, chyba że IDE wskazuje witrynę wyjątku
Farid
4

Szukałem również passmetody dla JUnit, abym mógł zwierać niektóre testy, które nie miały zastosowania w niektórych scenariuszach (są testy integracyjne, a nie czyste testy jednostkowe). Więc szkoda, że ​​go nie ma.

Na szczęście jest sposób na warunkowe zignorowanie testu, co w rzeczywistości pasuje jeszcze lepiej w moim przypadku przy użyciu assumeTruemetody:

Assume.assumeTrue (isTestApplicable);

Więc tutaj test zostanie wykonany tylko wtedy, gdy isTestApplicable ma wartość true, w przeciwnym razie test zostanie zignorowany.

Sebastian K.
źródło
2

Nie ma potrzeby stosowania metody pass, ponieważ gdy nie zostanie zgłoszony wyjątek AssertionFailedException z kodu testu, przypadek testu jednostkowego zostanie przekazany.

Metoda fail () w rzeczywistości zgłasza wyjątek AssertionFailedException w celu odrzucenia testu testCase, jeśli kontrola dojdzie do tego punktu.

Ajay
źródło
Myślę, że to właściwie junit.framework.AssertionFailedError.
Kyle
A co z przypadkami błędów. powiedz, że otrzymuję element niewidoczny, wyjątek od webdriver. Powinienem przechwycić wyjątek i zwrócić.
sasikumar
1

Myślę, że to pytanie jest wynikiem małego niezrozumienia procesu wykonywania testów. W JUnit (i innych narzędziach testujących) wyniki są liczone według metody, a nie dla wywołania assert. Nie ma licznika, który śledzi, ile assertXwykonano pomyślnie / zakończonych niepowodzeniem .

JUnit wykonuje każdą metodę testową oddzielnie. Jeśli metoda zakończy się pomyślnie, test zostanie zarejestrowany jako „zaliczony”. Jeśli wystąpi wyjątek, test zarejestrowany jako „nie powiódł się”. W tym drugim przypadku możliwe są dwie subprzypadki: 1) wyjątek asercji JUnit, 2) dowolny inny rodzaj wyjątków. W pierwszym przypadku stan będzie oznaczony jako „błąd”, w drugim „błąd”.

W Assertklasie dostępnych jest wiele metod skrótowych do rzucania wyjątków asercji. Innymi słowy, Assertjest warstwą abstrakcji ponad wyjątkami JUnit.

Na przykład to jest kod źródłowy assertEqualsna GitHub :

/**
 * Asserts that two Strings are equal.
 */
static public void assertEquals(String message, String expected, String actual) {
    if (expected == null && actual == null) {
        return;
    }
    if (expected != null && expected.equals(actual)) {
        return;
    }
    String cleanMessage = message == null ? "" : message;
    throw new ComparisonFailure(cleanMessage, expected, actual);
}

Jak widać, w przypadku równości nic się nie dzieje, w przeciwnym razie zostanie rzucony wyjątek.

Więc:

assertEqual("Oh!", "Some string", "Another string!");

po prostu zgłasza ComparisonFailurewyjątek, który zostanie przechwycony przez JUnit, a

assertEqual("Oh?", "Same string", "Same string");

nic nie robi.

Podsumowując, coś takiego pass()nie miałoby sensu, bo nic nie dało.

Dávid Horváth
źródło