Jak sprawdzić, czy w moim teście jednostkowym MSTest nie wystąpił wyjątek?


88

Piszę test jednostkowy dla tej metody, która zwraca „void”. Chciałbym mieć jeden przypadek, w którym test przechodzi pomyślnie, gdy nie został zgłoszony żaden wyjątek. Jak to napisać w C #?

Assert.IsTrue(????)

(Domyślam się, że tak powinienem sprawdzić, ale co wchodzi w skład „???”)

Mam nadzieję, że moje pytanie jest wystarczająco jasne.


Czy używasz MSTest lub NUnit?
Matt Grande,

2
W MSTest nieprzechwycone wyjątki automatycznie spowodują niepowodzenie testów. Czy próbujesz uwzględnić przechwycone wyjątki?
Phil

Możesz wyszukać „try-catch for C #”, a to poinstruuje Cię, jak obsługiwać zgłaszane lub nie zgłaszane wyjątki.
Foggzie,

1
Jeśli NUnit, spójrz na Assert.That (lambda) .Throws.Nothing (Chociaż myślę, że to się ostatnio zmieniło)
Matt Grande

Odpowiedzi:


138

Twój test jednostkowy i tak zakończy się niepowodzeniem, jeśli zostanie zgłoszony wyjątek - nie musisz umieszczać specjalnego potwierdzenia.

Jest to jeden z niewielu scenariuszy, w których zobaczysz testy jednostkowe bez żadnych asercji - test niejawnie zakończy się niepowodzeniem, jeśli zostanie zgłoszony wyjątek.

Jeśli jednak naprawdę chciałeś napisać asercję w tym celu - być może aby móc wychwycić wyjątek i zgłosić „nie spodziewałem się wyjątku, ale dostałem to ...”, możesz to zrobić:

[Test]
public void TestNoExceptionIsThrownByMethodUnderTest()
{
    var myObject = new MyObject();

    try
    {
        myObject.MethodUnderTest();
    }
    catch (Exception ex)
    {
        Assert.Fail("Expected no exception, but got: " + ex.Message);
    }
}

(powyższe jest przykładem dla NUnit, ale to samo dotyczy MSTest)


Oczywiście nie powinieneś łapać takich wyjątków, aby to było prawdą.
Servy

7
Test zakończy się niepowodzeniem tylko wtedy, gdy zostanie zgłoszony nieprzechwycony wyjątek. W zależności od kodu w programach obsługi wyjątków testy jednostkowe mogą przejść.
ediblecode

1
Jest to przydatne dla Ms Unittest, więc nie ma metody Assert.DoesNotThrow (() w Unittest.
Başar Kaya,

25

W NUnit możesz użyć:

Assert.DoesNotThrow(<expression>); 

aby zapewnić, że Twój kod nie zgłasza wyjątku. Chociaż test zakończy się niepowodzeniem, jeśli wyjątek zostanie zgłoszony, nawet jeśli nie było wokół niego Assert, wartość tego podejścia polega na tym, że możesz następnie rozróżnić niespełnione oczekiwania i błędy w testach, a także masz możliwość dodania niestandardowego komunikatu, który zostanie wyświetlony w wyniku testu. Dobrze sformułowane wyniki testu mogą pomóc w zlokalizowaniu błędów w kodzie, które spowodowały niepowodzenie testu.

Myślę, że warto dodać testy, aby upewnić się, że kod nie wyrzuca wyjątków; na przykład wyobraź sobie, że sprawdzasz poprawność danych wejściowych i musisz przekonwertować przychodzący ciąg na długi. Mogą wystąpić sytuacje, w których ciąg ma wartość null i jest to akceptowalne, więc chcesz się upewnić, że konwersja ciągu nie zgłosi wyjątku. Będzie zatem kod, który poradzi sobie z tą sytuacją, a jeśli nie napisałeś dla niego testu, stracisz pokrycie ważnej części logiki.


1
Wyraźny tekst DoesNotThrow jest fajny. Jeśli jesteś przyzwyczajony do oglądania Asserta. * Podczas testu, możesz pomyśleć, że drugi facet był leniwy i zapomniał.
Matt Beckman,

Czy istnieje odpowiednik tego w programie vstest lub mstest?
Dan Csharpster

1
@DanCsharpster, nie sądzę, żeby było, przynajmniej w MSTest - kiedy potrzebowałem tej funkcji w MSTest w przeszłości, zrobiłem coś takiego: public class TestBase { //believe me, I don't like this anymore than you do. protected void AssertDoesNotThrow(Action action, string message) { try { action(); } catch (Exception) { Assert.Fail(message); } } }
Clarkeye

@Clarkeye, to ciekawy pomysł. Dzięki! Miejmy nadzieję, że nauczą się lepiej kopiować NUnit w przyszłych wersjach. Myślałem również o napisaniu adaptera między vstest a NUnit.
Dan Csharpster

@DanCsharpster, jedną rzeczą, na którą warto się przyjrzeć, są płynne asercje, które mają dobre wsparcie dla ShouldThrow i ShouldNotThrow: github.com/dennisdoomen/fluentassertions/wiki#exceptions . Dokumentacja twierdzi, że jest kompatybilny z MSTest (chociaż używałem go tylko z XUnit i NUnit). Może nie robić wszystkiego, co chcesz, ale i tak możesz połączyć to z asercjami MSTest.
Clarkeye

11

Nie sprawdzaj, czy coś się nie dzieje . To jak zapewnienie, że kod się nie psuje . To trochę zasugerowane, wszyscy dążymy do nierozerwalnego, pozbawionego błędów kodu. Chcesz napisać testy? Dlaczego tylko jedna metoda? Czy nie chcesz, aby wszystkie twoje metody były testowane, aby nie rzucały wyjątków ? Podążając tą drogą, otrzymasz jeden dodatkowy, fikcyjny, pozbawiony potwierdzenia test dla każdej metody w bazie kodu. Nie ma wartości.

Oczywiście, jeśli wymogiem jest, aby zweryfikować sposób robi wyjątki połowowe , zrobić test, który (lub odwrócenie go trochę, test, że nie rzuca to, co ma do połowu).

Jednak ogólne podejście / praktyki pozostają nienaruszone - nie piszesz testów dla niektórych sztucznych / niejasnych wymagań, które są poza zakresem testowanego kodu (a testowanie, czy „działa” lub „nie rzuca” jest zwykle przykładem takie - szczególnie w scenariuszu, w którym obowiązki metody są dobrze znane).

Mówiąc prościej - skoncentruj się na tym, co ma robić Twój kod i przetestuj to.


10
-1 przychodzi mi do głowy pozytywna funkcjonalność, która wymaga i nie należy wyrzucać wyjątku. Po pierwsze - metoda, której zadaniem jest obsługa wyjątków, rejestrowanie ich i podejmowanie działań - bez dalszego rzucania wyjątku. Podajesz dobrą ogólną uwagę - ale potem mów absolutnie tak, jakby zawsze było prawdą.
Rob Levine,

3
@RobLevine: Rozumiem twój przykład i zdaję sobie sprawę, że piszesz testy w takich przypadkach. Jednak, jak zauważyłeś, rzeczywiście chodziło mi o bardziej ogólną praktykę - że tak powiem, testowanie tego, co ma robić twój kod, w porównaniu z testowaniem tego, czego twój kod nie robi. Trochę przeformułowałem swój post, aby mój punkt widzenia był bardziej jasny i bliższy temu, co miałem na myśli. Daje również możliwość ponownego rozważenia swojego głosu. Dziękuję za wyjaśnienie i przepraszam za opóźnioną odpowiedź.
km

4
głos przeciw został usunięty - następnym razem nie będę tak zadowolony z głosowania przeciwnego!
Rob Levine,

4
W naszym projekcie mamy klasę htmlvalidator, która rzuca wyjątki jeśli html jest nieprawidłowy. Na przykład, gdy użytkownik wprowadza (za pomocą konsoli) javascript w bogatej kombinacji. Więc w moim kodzie przypadku to, co robi mój kod, to nie rzucanie wyjątków (podejście z białą listą) i muszę to przetestować.
Machet

1
Nie zgadzam się z tą odpowiedzią. Testowanie pod kątem braku czegoś, czasami w pewnym scenariuszu, może być ważnym testem.
bytedev

7

Ta klasa pomocnicza podrapała mnie po swędzeniu dzięki MSTest. Może to też może porysować twoje.

[TestMethod]
public void ScheduleItsIneligibilityJob_HasValid_CronSchedule()
{
    // Arrange
    var factory = new StdSchedulerFactory();
    IScheduler scheduler = factory.GetScheduler();

    // Assert
    AssertEx.NoExceptionThrown<FormatException>(() =>
        // Act
        _service.ScheduleJob(scheduler)
    );
}

public sealed class AssertEx
{
    public static void NoExceptionThrown<T>(Action a) where T:Exception
    {
        try
        {
            a();
        }
        catch (T)
        {
            Assert.Fail("Expected no {0} to be thrown", typeof(T).Name);
        }
    }
}

@Remco Beurskens - dodanie ogólnego catch {} na końcu NoExceptionThrown <T> pominie inne błędy, co nie jest zamierzoną konsekwencją metody. Nie jest to metoda ogólnego przeznaczenia do pomijania wszystkich wyjątków. Jest przeznaczona do niepowodzenia tylko wtedy, gdy zostanie zgłoszony wyjątek znanego typu.
JJS,

1
Jest to teraz bardzo stare, ale Assertma pojedynczy element dostępu do właściwości, Thatktórego można użyć jako punktu zaczepienia dla metod rozszerzających. To może być schludniej i bardziej wykrywalne, aby Assert.That.DoesNotThrow()zamiast AssertEx.DoesNotThrow(). To tylko opinia.
Richard Hauer

3

Lubię widzieć Assert.Whateverna końcu każdego testu, tylko dla spójności ... bez jednego, czy naprawdę mogę być pewien, że takiego nie powinno tam być?

Dla mnie jest to tak proste, jak wprowadzenie Assert.IsTrue(true);

Ja wiem, że nie przypadkowo umieścić ten kod tam, a zatem powinien być na tyle pewnie, a przy szybkim przejrzeć że to był zgodnie z przeznaczeniem.

    [TestMethod]
    public void ProjectRejectsGappedVersioningByDefault() {

        var files = new List<ScriptFile>();
        files.Add(ScriptProjectTestMocks.GetVersion1to2());
        files.Add(ScriptProjectTestMocks.GetVersion3to4());

        Assert.Throws<ScriptProject.InvalidProjectFormatException>(() => {
            var sut = new ScriptProject(files);
        });

    }

    [TestMethod]
    public void ProjectAcceptsGappedVersionsExplicitly() {

        var files = new List<ScriptFile>();
        files.Add(ScriptProjectTestMocks.GetVersion1to2());
        files.Add(ScriptProjectTestMocks.GetVersion3to4());

        var sut = new ScriptProject(files, true);

        Assert.IsTrue(true);   // Assert.Pass() would be nicer... build it in if you like

    }

To nie to samo. Jeśli kod zostanie zgłoszony, żadne potwierdzenie nie zostanie trafione, a przebieg testowy zakończy się niepowodzeniem. Chcesz podłączyć się do struktury testowej, potwierdzając warunek.
DvS

1

Mój przyjaciel Tim powiedział mi o ExpectedException . Naprawdę podoba mi się ta b / c, jest bardziej zwięzła, mniej kodu i bardzo wyraźna, że ​​testujesz pod kątem wyjątku.

[TestMethod()]
[ExpectedException(typeof(System.Exception))]
public void DivideTest()
{
    int numerator = 4;
    int denominator = 0;
    int actual = numerator / denominator;
}

Możesz przeczytać o wiele więcej na ten temat tutaj: ExpectedException Attribute Usage .


1
PO prosi o żaden wyjątek.
Daniel A. White

Zostawię tę odpowiedź tutaj. Znalazłem to pytanie podczas wyszukiwania w Google, jak sprawdzić wyjątki i myślę, że ta odpowiedź musi być tutaj. PO otrzymał odpowiedź na swoje pytanie 7 lat temu. Myślę, że nawet link do drugiej odpowiedzi jest pomocny.
Jess,

Dobry stary Tim. 🤔
ruffin
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.