Comment attraper une exception dans MSTest sans perdre la tête ?
\n\nVous écrivez des tests unitaires en C# et soudain vous réalisez : votre méthode doit lever une exception dans une situation donnée. Comment le vérifier ? Si vous avez cherché sur Google « How do I use Assert to verify that an exception has been thrown with MSTest », vous n'êtes pas seul — c'est l'une des questions les plus populaires sur Stack Overflow. Et aujourd'hui, nous allons l'éclaircir une fois pour toutes.
\n\nDans cet article, je vais vous montrer toutes les façons de vérifier les exceptions dans MSTest : de l'attribut classique au moderne Assert.ThrowsException. Vous apprendrez à écrire des tests propres et fiables qui ne tomberont pas au pire moment. C'est parti !
Pourquoi la vérification des exceptions est-elle importante ?
\n\nImaginez : vous avez une méthode Divide(int a, int b). Si b = 0, elle doit lever une DivideByZeroException. Sans test, vous ne le saurez que lorsque l'application plantera en production. Un test unitaire avec vérification d'exception est votre filet de sécurité.
Dans MSTest (framework de tests unitaires de Microsoft), il existe plusieurs approches. Nous allons examiner chacune, mais commençons par la plus moderne et recommandée.
\n\nMéthode 1 : Assert.ThrowsException (La plus correcte)
\n\nDepuis MSTest V2 (version 2.x), nous avons une méthode intégrée Assert.ThrowsException<T>. C'est élégant, lisible et flexible. La syntaxe est simple :
[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\nQue se passe-t-il ici ? Nous passons une expression lambda avec l'appel de la méthode. MSTest l'exécute dans un bloc try-catch. Si l'exception n'est PAS levée — le test échoue. Si une exception d'un autre type est levée — il échoue aussi. Seule l'exception attendue mène au succès.
\n\nExemple avancé : vérification du message de l'exception
\n\nParfois, il faut vérifier non seulement le type de l'exception, mais aussi son message. Pour cela, utilisez la surcharge avec le paramètre message ou vérifiez les propriétés de l'objet exception :
[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 supplémentaire\n Assert.AreEqual("Id must be positive", exception.Message);\n}\n\nNotez que Assert.ThrowsException retourne l'objet exception ! Cela vous permet de vérifier n'importe laquelle de ses propriétés : InnerException, Data, StackTrace (bien que ce dernier ne soit généralement pas vérifié).
Méthode 2 : Attribut [ExpectedException] (Obsolète, mais encore utilisé)
\n\nAvant (dans MSTest V1), on utilisait un attribut sur la méthode de test elle-même. Cela ressemblait à ceci :
\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\nCela semble pratique ? Mais il y a trois problèmes :
\n- \n
- Impossible de vérifier le message de l'exception. Vous ne savez pas si c'est la bonne exception qui est levée. \n
- Toute exception de ce type est un succès. Même si elle provient d'une autre ligne de code (par exemple, dans Arrange). \n
- Impossible d'exécuter du code après l'exception. La méthode de test s'interrompt immédiatement. \n
C'est pourquoi, dans les nouveaux projets, utilisez Assert.ThrowsException. L'attribut [ExpectedException] est marqué comme deprecated (obsolète) et pourrait être supprimé dans les versions futures.
Méthode 3 : Try-catch manuel (Pour les extrémistes)
\n\nParfois (très rarement), vous avez be