如何使用Assert.Throws
断言异常的类型和实际的消息措辞。
这样的事情:
Assert.Throws<Exception>(
()=>user.MakeUserActive()).WithMessage("Actual exception message")
我正在测试的方法会抛出相同类型的多条消息,但是我需要一种方法来测试是否会根据上下文抛出正确的消息。
答案 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>());