Wie fängt man eine Ausnahme in MSTest ab, ohne verrückt zu werden?
\n\nSie schreiben Unit-Tests in C# und stellen plötzlich fest: Ihre Methode soll in einer bestimmten Situation eine Ausnahme auslösen. Wie testen Sie das? Wenn Sie gegoogelt haben „How do I use Assert to verify that an exception has been thrown with MSTest“, dann sind Sie nicht allein – das ist eine der häufigsten Fragen auf Stack Overflow. Und heute klären wir das ein für alle Mal.
\n\nIn diesem Artikel zeige ich Ihnen alle Möglichkeiten, Ausnahmen in MSTest zu testen: vom klassischen Attribut bis zum modernen Assert.ThrowsException. Sie erfahren, wie Sie saubere, zuverlässige Tests schreiben, die nicht im ungünstigsten Moment fehlschlagen. Los geht's!
Warum ist das Testen von Ausnahmen wichtig?
\n\nStellen Sie sich vor: Sie haben eine Methode Divide(int a, int b). Wenn b = 0 ist, soll sie eine DivideByZeroException auslösen. Ohne Test erfahren Sie das erst, wenn die Anwendung in der Produktion abstürzt. Ein Unit-Test mit Ausnahmeprüfung ist Ihr Sicherheitsnetz.
In MSTest (dem Framework für Modultests von Microsoft) gibt es mehrere Ansätze. Wir werden jeden betrachten, beginnen aber mit dem modernsten und empfohlenen.
\n\nMethode 1: Assert.ThrowsException (Die korrekteste)
\n\nSeit MSTest V2 (Version 2.x) gibt es die integrierte Methode Assert.ThrowsException<T>. Sie ist elegant, lesbar und flexibel. Die Syntax ist einfach:
[TestMethod]\npublic void Divide_ByZero_ThrowsDivideByZeroException()\n{\n // Arrange\n var calculator = new Calculator();\n\n // Act & Assert\n Assert.ThrowsException<DivideByZeroException>(() => calculator.Divide(10, 0));\n}\n\nWas passiert hier? Wir übergeben einen Lambda-Ausdruck mit dem Methodenaufruf. MSTest führt ihn innerhalb eines try-catch-Blocks aus. Wenn KEINE Ausnahme ausgelöst wird – schlägt der Test fehl. Wenn eine Ausnahme eines anderen Typs ausgelöst wird – schlägt er ebenfalls fehl. Nur die gewünschte Ausnahme führt zum Erfolg.
\n\nFortgeschrittenes Beispiel: Prüfung der Ausnahmemeldung
\n\nManchmal muss man nicht nur den Typ der Ausnahme, sondern auch deren Meldung überprüfen. Dazu verwenden Sie die Überladung mit dem Parameter message oder prüfen die Eigenschaften des Ausnahmeobjekts:
[TestMethod]\npublic void GetUserById_InvalidId_ThrowsWithCorrectMessage()\n{\n // Arrange\n var service = new UserService();\n\n // Act\n var exception = Assert.ThrowsException<ArgumentException>(() => service.GetUserById(-1));\n\n // Assert zusätzlich\n Assert.AreEqual("Id must be positive", exception.Message);\n}\n\nBeachten Sie: Assert.ThrowsException gibt das Ausnahmeobjekt zurück! So können Sie alle seine Eigenschaften überprüfen: InnerException, Data, StackTrace (auch wenn letzteres normalerweise nicht geprüft wird).
Methode 2: Das Attribut [ExpectedException] (Veraltet, aber noch in Gebrauch)
\n\nFrüher (in MSTest V1) wurde ein Attribut über der Testmethode selbst verwendet. Das sah so aus:
\n\n[TestMethod]\n[ExpectedException(typeof(DivideByZeroException))]\npublic void Divide_ByZero_ThrowsDivideByZeroException_OldWay()\n{\n var calculator = new Calculator();\n calculator.Divide(10, 0);\n}\n\nScheint praktisch? Aber es gibt drei Probleme:
\n- \n
- Die Ausnahmemeldung kann nicht geprüft werden. Sie wissen nicht, ob die richtige Ausnahme ausgelöst wurde. \n
- Jede Ausnahme dieses Typs ist ein Erfolg. Selbst wenn sie aus einer anderen Codezeile stammt (z. B. im Arrange-Teil). \n
- Nach der Ausnahme kann kein Code mehr ausgeführt werden. Die Testmethode wird sofort unterbrochen. \n
Verwenden Sie daher in neuen Projekten Assert.ThrowsException. Das Attribut [ExpectedException] ist als deprecated (veraltet) markiert und könnte in zukünftigen Versionen entfernt werden.
Methode 3: Manuelles try-catch (Für Extremfälle)
\n\nManchmal (sehr selten) benötigen Sie