web-dev-qa-db-fra.com

Comment utiliser Assert.Throws pour affirmer le type de l'exception?

Comment utiliser Assert.Throws pour affirmer le type de l'exception et la formulation du message.

Quelque chose comme ça:

Assert.Throws<Exception>(
    ()=>user.MakeUserActive()).WithMessage("Actual exception message")

La méthode que je teste envoie plusieurs messages du même type, avec des messages différents, et j'ai besoin d'un moyen de vérifier que le message correct est envoyé en fonction du contexte.

219
epitka

Assert.Throws renvoie l'exception levée qui vous permet d'affirmer l'existence de l'exception.

var ex = Assert.Throws<Exception>(() => user.MakeUserActive());
Assert.That(ex.Message, Is.EqualTo("Actual exception message"));

Ainsi, si aucune exception n'est levée ou si une exception du type incorrect est levée, la première assertion Assert.Throws échouera. Cependant, si une exception du type correct est levée, vous pouvez maintenant affirmer sur l'exception réelle que vous avez enregistrée dans la variable.

En utilisant ce modèle, vous pouvez affirmer autre chose que le message d'exception, par exemple: dans le cas de ArgumentException et de ses dérivés, vous pouvez affirmer que le nom du paramètre est correct:

var ex = Assert.Throws<ArgumentNullException>(() => foo.Bar(null));
Assert.That(ex.ParamName, Is.EqualTo("bar"));

Vous pouvez également utiliser l'API fluide pour effectuer ces assertions:

Assert.That(() => foo.Bar(null), 
Throws.Exception
  .TypeOf<ArgumentNullException>()
  .With.Property("ParamName")
  .EqualTo("bar"));

Un petit conseil lors de l’affirmation de messages d’exception consiste à décorer la méthode de test avec SetCultureAttribute pour s’assurer que le message émis utilise la culture attendue. Cela entre en jeu si vous stockez vos messages d'exception sous forme de ressources pour permettre la localisation.

396
Patrik Hägne

Vous pouvez maintenant utiliser les attributs ExpectedException, par exemple.

[Test]
[ExpectedException(typeof(InvalidOperationException), 
 ExpectedMessage="You can't do that!"]
public void MethodA_WithNull_ThrowsInvalidOperationException()
{
    MethodA(null);
}
24
Jackson Pope
Assert.That(myTestDelegate, Throws.ArgumentException
    .With.Property("Message").EqualTo("your argument is invalid."));
13
Jordan Morris

C'est une question ancienne mais pertinente avec des réponses obsolètes alors j'ajoute la solution actuelle:

public void Test() {
    throw new MyCustomException("You can't do that!");
}

[TestMethod]
public void ThisWillPassIfExceptionThrown()
{
    var exception = Assert.ThrowsException<MyCustomException>(
        () => Test(),
        "This should have thrown!");
    Assert.AreEqual("You can't do that!", exception.Message);
}

Cela fonctionne avec using Microsoft.VisualStudio.TestTools.UnitTesting;

3
Tvde1

Pour développer la réponse de persistent, et pour fournir davantage de fonctionnalités de NUnit, vous pouvez procéder comme suit:

public bool AssertThrows<TException>(
    Action action,
    Func<TException, bool> exceptionCondition = null)
    where TException : Exception 
{
    try
    {
        action();
    }
    catch (TException ex)
    {
        if (exceptionCondition != null)
        {
            return exceptionCondition(ex);
        }

        return true;
    }
    catch
    {
        return false;
    }

    return false; 
}

Exemples:

// No exception thrown - test fails.
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
        () => {}));

// Wrong exception thrown - test fails.
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
        () => { throw new ApplicationException(); }));

// Correct exception thrown - test passes.
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
        () => { throw new InvalidOperationException(); }));

// Correct exception thrown, but wrong message - test fails.
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
        () => { throw new InvalidOperationException("ABCD"); },
        ex => ex.Message == "1234"));

// Correct exception thrown, with correct message - test passes.
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
        () => { throw new InvalidOperationException("1234"); },
        ex => ex.Message == "1234"));
3
fre0n

Je me rends bien compte que cette question a été soulevée depuis longtemps, mais je me suis récemment retrouvé dans la même situation et suggère cette fonction pour MSTest:

public bool AssertThrows(Action action) where T : Exception 
{ 
try {action();} 
catch(Exception exception) 
{ 
    if (exception.GetType() == typeof(T)) return true; 
} 
return false; 
}

usage:

Assert.IsTrue(AssertThrows<FormatException>(delegate{ newMyMethod(MyParameter); }));

Plus ici: http://phejndorf.wordpress.com/2011/02/21/assert-that-a-particular-exception-has-occured/

2
persistent

Comme je suis dérangé par la verbosité de certains des nouveaux modèles NUnit, j’utilise quelque chose comme ceci pour créer un code plus propre pour moi personnellement:

public void AssertBusinessRuleException(TestDelegate code, string expectedMessage)
{
    var ex = Assert.Throws<BusinessRuleException>(code);
    Assert.AreEqual(ex.Message, expectedMessage);
}

public void AssertException<T>(TestDelegate code, string expectedMessage) where T:Exception
{
    var ex = Assert.Throws<T>(code);
    Assert.AreEqual(ex.Message, expectedMessage);
}

L'utilisation est alors:

AssertBusinessRuleException(() => service.Create(content), "Name already exists");
1
Savage