Użyć metody NUnit Assert.Throws lub atrybutu ExpectedException?

146

Odkryłem, że wydaje się, że są to dwa główne sposoby testowania wyjątków:

Assert.Throws<Exception>(()=>MethodThatThrows());

[ExpectedException(typeof(Exception))]

Który z nich byłby najlepszy? Czy jedna oferuje przewagę nad drugą? Czy jest to po prostu kwestia osobistych preferencji?

SamuelDavis
źródło
3
Trzecią opcją jest płynny styl:Assert.That(() => MethodThatThrows(), Throws.Exception)
Jack Ukleja
1
NUnit w wersji 3 i nowszych nie obsługuje już tego ExpectedExceptionatrybutu, więc w przypadku wersji 3+ Assert.Throwsistotny jest tylko wariant.
joanlofe
Dlaczego tak się dzieje? Że Nunit3 zdecydował się zrezygnować z tego wsparcia? Szukałem w Google i nie mogłem znaleźć wyjaśnienia ... JUnit nadal obsługuje ten sposób, prawda?
ahaaman

Odpowiedzi:

92

Pierwsza umożliwia testowanie pod kątem więcej niż jednego wyjątku z wieloma wywołaniami:

Assert.Throws(()=>MethodThatThrows());
Assert.Throws(()=>Method2ThatThrows());

Druga pozwala tylko na przetestowanie jednego wyjątku na funkcję testową.

chue x
źródło
25
Test powinien testować tylko jeden odrębny bit logiki, więc czy testowanie dwóch błędów w tym samym teście jednostkowym nie byłoby uważane za złą praktykę?
SamuelDavis
5
@SamuelDavis - generalnie nie chciałbyś testować różnych przypadków w tym samym teście. Jednak mogą istnieć przypadki użycia wielu plików Assert.Throws.
chue x
3
Tak czy inaczej, tutaj otrzymasz wyjątek jako parametr, który umożliwia potwierdzenie szczegółów w wyjątku. Ponadto użycie „Oczekiwanego wyjątku” nie chroni Cię przed tym samym typem wyjątku, który jest zgłaszany w innym wywołaniu metody. Tutaj celem jest dokładna metoda, a nie cały test. Nawet jeśli twój test powinien wywoływać bardzo mało kodu, nigdy nie jesteś zbyt bezpieczny. Zwłaszcza, gdy kod staje się złożony i / lub wyjątek jest zbyt ogólny. Rzeczy takie jak „ArgumentNullExceptions” mogą być rzucane często i na przykład można je łatwo przeoczyć za pomocą ExpectedException. Assert.Throws by tego nie przegapił.
Gil Sand
254

Główna różnica to:

ExpectedException()Atrybut sprawia, że ​​test przechodzi pomyślnie, jeśli wyjątek wystąpi w dowolnym miejscu metody testowej.
Użycie Assert.Throws()pozwala określić exactmiejsce kodu, w którym oczekiwany jest wyjątek.

NUnit 3.0 ExpectedExceptioncałkowicie rezygnuje z oficjalnego wsparcia .

Dlatego zdecydowanie wolę używać Assert.Throws()metody niż ExpectedException()atrybutu.

Aleksandra Stepaniuka
źródło
7
To zdecydowanie poprawna odpowiedź. Nawiasem mówiąc, Assert.Throws () zwraca również wyjątek, który może pozwolić na dodatkową kontrolę właściwości wyjątku, jeśli mają one dla Ciebie znaczenie.
perfekcjonista
1
Na koniec odpowiedz, dlaczego nie mogę uruchomić ExpectedException .. z wersją 3.
Styczeń
2
Oto link github.com/nunit/docs/wiki/Breaking-Changes - ExpectedExceptionAttribute nie jest już obsługiwany.
Anton Lyhin
Aby to zmienić, aby działało pod NUnit 3.0, zmień to na następujące
Andrei Krasutski
38

Wolę assert.throws, ponieważ umożliwia mi weryfikację i zapewnienie innych warunków po zgłoszeniu wyjątku.

    [Test]
    [Category("Slow")]
    public void IsValidLogFileName_nullFileName_ThrowsExcpetion()
    {
        // the exception we expect thrown from the IsValidFileName method
        var ex = Assert.Throws<ArgumentNullException>(() => a.IsValidLogFileName(""));

        // now we can test the exception itself
        Assert.That(ex.Message == "Blah");

    }
Mike Parkhill
źródło
To jedna z lepszych odpowiedzi. Często zdarza się, że chcesz sprawdzić, czy coś weszło w stan błędu po zgłoszeniu wyjątku.
Rhys Bevilaqua
11

Możesz również silnie wpisać oczekiwany błąd (jak stara wersja atrybutu).

Assert.Throws<System.InvalidOperationException>(() => breakingAction())
Wielebny Sfinks
źródło