如何使用Assert.Throws来断言异常的类型?

时间:2009-10-22 19:46:14

标签: c# exception nunit assertions

如何使用Assert.Throws断言异常的类型和实际的消息措辞。

这样的事情:

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

我正在测试的方法会抛出相同类型的多条消息,但是我需要一种方法来测试是否会根据上下文抛出正确的消息。

8 个答案:

答案 0 :(得分:379)

Assert.Throws返回抛出的异常,它允许您对异常进行断言。

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

因此,如果没有抛出异常,或抛出错误类型的异常,则第一个Assert.Throws断言将失败。但是,如果抛出了正确类型的异常,那么现在可以断言已保存在变量中的实际异常。

通过使用此模式,您可以断言除异常消息之外的其他内容,例如在ArgumentException和衍生物的情况下,您可以断言参数名称是正确的:

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

您还可以使用Fluent API执行这些断言:

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

在异常消息上断言时的一个小提示是使用SetCultureAttribute修饰测试方法,以确保抛出的消息正在使用预期的文化。如果您将异常消息存储为允许本地化的资源,则会发挥作用。

答案 1 :(得分:24)

您现在可以使用ExpectedException属性,例如

[Test]
[ExpectedException(typeof(InvalidOperationException), 
 ExpectedMessage="You can't do that!"]
public void MethodA_WithNull_ThrowsInvalidOperationException()
{
    MethodA(null);
}

答案 2 :(得分:13)

Assert.That(myTestDelegate, Throws.ArgumentException
    .With.Property("Message").EqualTo("your argument is invalid."));

答案 3 :(得分:3)

要扩展持久性的答案,并提供更多NUnit的功能,您可以这样做:

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; 
}

示例:

// 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"));

答案 4 :(得分:2)

自从这个问题提出以来已经有很长一段时间了,我意识到,但我最近碰到了同样的事情,并为MSTest建议了这个功能:

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

用法:

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

更多信息:http://phejndorf.wordpress.com/2011/02/21/assert-that-a-particular-exception-has-occured/

答案 5 :(得分:2)

这是一个古老而相关的问题,答案已经过时,因此我要添加当前的解决方案:

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

[TestMethod]
public void ThisWillPassIfExceptionThrown()
{
    Assert.ThrowsException<MyCustomException>(
        () => Test(),
        "You can't do that!");
}

这与using Microsoft.VisualStudio.TestTools.UnitTesting;

一起使用

答案 6 :(得分:1)

由于我对一些新的NUnit模式的冗长感到不安,我使用这样的东西来创建对我个人来说更清洁的代码:

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);
}

然后使用:

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

答案 7 :(得分:1)

对于那些使用 NUnit 3.0 Constraint Model 并在此处结束的人:

Assert.That(() => MethodUnderTest(someValue), Throws.TypeOf<ArgumentException>());