936 votes

Comment puis-je utiliser Assert pour vérifier qu'une exception a été levée avec MSTest ?

Comment utiliser Assert (ou une autre classe de Test) pour vérifier qu'une exception a été levée lors de l'utilisation de MSTest/Microsoft.VisualStudio.TestTools.UnitTesting?

0 votes

Quel framework de tests unitaires utilisez-vous?

4 votes

S'il vous plaît traduire cela en gardant les mêmes balises HTML s'il y en a : Intégré dans Visual Studio

4 votes

Le attribut ExpectedException ne fonctionne-t-il pas? ref : msdn.microsoft.com/en-us/library/…

1078voto

Kevin Pullin Points 4663

Pour "Visual Studio Team Test", il semble que vous appliquiez l'attribut ExpectedException à la méthode de test.

Exemple de la documentation ici : Une présentation des tests unitaires avec Visual Studio Team Test

[TestMethod]
[ExpectedException(typeof(ArgumentException),
    "Un identifiant utilisateur nul a été inappropriément autorisé.")]
public void NullUserIdInConstructor()
{
   LogonInfo logonInfo = new LogonInfo(null, "P@ss0word");
}

27 votes

L'attribut ExpectedException ci-dessus fonctionne également dans NUnit (mais [TestMethod] devrait être [Test]).

6 votes

@dbkk: Ne fonctionne pas exactement de la même manière dans NUnit - le message est traité comme une chaîne de caractères qui doit correspondre au message de l'exception (et je pense que cela a plus de sens)

31 votes

Cet attribut fait le travail et est une fonctionnalité intégrée pour les programmeurs c#, mais je ne recommande pas de l'utiliser car il n'est pas assez flexible. Considérez ce qui se passe si le type d'exception est lancé par votre code de configuration de test : le test réussit, mais n'a pas fait ce que vous attendiez. Ou si vous voulez tester l'état de l'objet d'exception. J'ai généralement envie d'utiliser StringAssert.Contains(e.Message...) plutôt que de tester le message entier. Utilisez une méthode d'assertion comme décrit dans d'autres réponses.

280voto

ojrac Points 6897

En général, votre framework de test aura une réponse à cela. (Consultez les commentaires de ce fil pour des exemples, il y en a beaucoup !) Mais si votre framework n'est pas assez flexible, vous pouvez toujours faire ceci :

try {
    quelqueChoseQuiDevraitLancerUneException();
    Assert.Fail(); // Si cela arrive à cette ligne, aucune exception n'a été lancée
} catch (BonneException) { }

Comme le souligne @Jonas, cela NE FONCTIONNE PAS pour attraper une Exception de base :

try {
    quelqueChoseQuiDevraitLancerUneException();
    Assert.Fail(); // lève une AssertionException
} catch (Exception) {
    // Attrape l'exception d'assertion, et le test passe
}

Si vous devez absolument attraper Exception, vous devez relancer le Assert.Fail(). Mais vraiment, c'est un signe que vous ne devriez pas écrire ceci à la main ; vérifiez les options de votre framework de test, ou voyez si vous pouvez lancer une exception plus significative à tester.

catch (AssertionException) { throw; }

Vous devriez pouvoir adapter cette approche à ce que vous voulez -- y compris spécifier quels types d'exceptions attraper. Si vous n'attendez que certains types, finalisez les blocs catch avec :

} catch (BonneException) {
} catch (Exception) {
    // pas le bon type d'exception
    Assert.Fail();
}

22 votes

+1, j'utilise cette méthode plutôt que l'attribut lorsque j'ai besoin de faire des assertions au-delà du simple type d'exception. Par exemple, que faire si l'on doit vérifier que certains champs de l'instance d'exception sont définis à certaines valeurs.

0 votes

J'aime cela parce que vous n'avez pas à spécifier le message d'erreur exact comme avec l'approche de l'attribut

2 votes

Vous n'êtes pas obligé de spécifier le message d'erreur. Cela suffit : [ExpectedException(typeof(ArgumentException))]

126voto

Richiban Points 381

Ma méthode préférée pour implémenter cela est d'écrire une méthode appelée Throws, et de l'utiliser comme n'importe quelle autre méthode Assert. Malheureusement, .NET ne vous permet pas d'écrire une méthode d'extension statique, donc vous ne pouvez pas utiliser cette méthode comme si elle appartenait réellement à la classe Assert intégrée; créez simplement une autre appelée MyAssert ou quelque chose de similaire. La classe ressemble à ceci:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace YourProject.Tests
{
    public static class MyAssert
    {
        public static void Throws( Action func ) where T : Exception
        {
            var exceptionThrown = false;
            try
            {
                func.Invoke();
            }
            catch ( T )
            {
                exceptionThrown = true;
            }

            if ( !exceptionThrown )
            {
                throw new AssertFailedException(
                    String.Format("Une exception de type {0} était attendue, mais pas lancée", typeof(T))
                    );
            }
        }
    }
}

Cela signifie que votre test unitaire ressemble à ceci:

[TestMethod()]
public void ExceptionTest()
{
    String testStr = null;
    MyAssert.Throws(() => testStr.ToUpper());
}

Ce qui ressemble et se comporte beaucoup plus comme le reste de vos syntaxes de test unitaire.

2 votes

Se débarrasser du booléen drapeau et placer le jeton directement après l'invocation pour une implémentation plus compacte.

13 votes

La seule chose qui rend cela meilleur est de faire en sorte que la fonction renvoie l'exception attrapée afin que vous puissiez continuer à affirmer que des choses comme les attributs sur l'exception sont corrects.

2 votes

Merci! Cela me semble être la meilleure approche car c'est une façon courte de tester plusieurs exceptions dans une méthode. C'est aussi beaucoup plus lisible.

63voto

Jon Limjap Points 46429

Si vous utilisez MSTest, qui n'avait initialement pas d'attribut ExpectedException, vous pourriez faire ceci :

try 
{
    SomeExceptionThrowingMethod()
    Assert.Fail("aucune exception lancée");
}
catch (Exception ex)
{
    Assert.IsTrue(ex is SpecificExceptionType);
}

3 votes

Cela fonctionne, mais je ne recommande pas cela en général car la logique est trop compliquée. Je ne dis pas que c'est tortueux, mais imaginez si vous écrivez ce bloc de code pour plusieurs tests - 10, 100 tests. Cette logique doit être externalisée vers une méthode d'assertion bien conçue. Voir d'autres réponses.

0 votes

Peut également utiliser Assert.IsInstanceOfType(ex, typeof(SpecificExceptionType);

36voto

jrista Points 20950

Méfiez-vous de l'utilisation de ExpectedException, car cela peut entraîner plusieurs pièges comme le démontre ici:

Lien

Et ici:

http://xunit.github.io/docs/comparisons.html

Si vous avez besoin de tester des exceptions, il existe des moyens moins critiqués. Vous pouvez utiliser la méthode try{act/fail}catch{assert}, qui peut être utile pour les frameworks qui n'ont pas de support direct pour les tests d'exception autres que ExpectedException.

Une meilleure alternative est d'utiliser xUnit.NET, qui est un framework de tests unitaires très moderne, tourné vers l'avenir et extensible qui a appris des erreurs de tous les autres et s'est amélioré. Une telle amélioration est Assert.Throws, qui fournit une syntaxe beaucoup plus claire pour l'assertion des exceptions.

Vous pouvez trouver xUnit.NET sur github: http://xunit.github.io/

4 votes

Notez que NUnit 2.5 prend également en charge la syntaxe de style Assert.Throws maintenant aussi - nunit.com/index.php?p=releaseNotes&r=2.5

0 votes

La façon dont les tests unitaires s'arrêtent pour vous informer de l'exception lors de l'utilisation de ExpectedException me rend fou. Pourquoi Microsoft a-t-il pensé que c'était une bonne idée d'avoir une étape manuelle dans les tests automatisés? Merci pour les liens.

0 votes

@Ant: MS a copié NUnit... donc la vraie question est, pourquoi NUnit a-t-il pensé que c'était une bonne idée ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X