C# 单元测试如何确认抛出了异常

C# 单元测试如何确认抛出了异常,c#,.net,unit-testing,exception,C#,.net,Unit Testing,Exception,我正在为一个c#类编写一个单元测试,我的一个测试应该会导致该方法在添加数据时引发异常。如何使用单元测试来确认抛出了异常?这取决于您使用的单元测试框架。在所有情况下,您都可以执行以下操作: [Test] public void MakeItGoBang() { Foo foo = new Foo(); try { foo.Bang(); Assert.Fail("Expected exception"); } c

我正在为一个c#类编写一个单元测试,我的一个测试应该会导致该方法在添加数据时引发异常。如何使用单元测试来确认抛出了异常?

这取决于您使用的单元测试框架。在所有情况下,您都可以执行以下操作:

[Test]
public void MakeItGoBang()
{
     Foo foo = new Foo();
     try
     {
         foo.Bang();
         Assert.Fail("Expected exception");
     }
     catch (BangException)
     { 
         // Expected
     }
}
在某些框架中,您可以向测试方法添加一个属性来表示预期的异常,也可以添加一个方法,例如:

[Test]
public void MakeItGoBang()
{
     Foo foo = new Foo();
     Assert.Throws<BangException>(() => foo.Bang());
}
[测试]
公共无效使其成为五子棋()
{
Foo-Foo=新的Foo();
Assert.Throws(()=>foo.Bang());
}

这样限制范围更好,因为如果您将其应用于整个测试,即使错误的行引发了异常,测试也可能通过。

如果您使用Nunit,您可以使用

[ExpectedException( "System.ArgumentException" ) )]
用于VisualStudio单元测试框架

见:

如果引发预期的异常,则测试方法将通过

如果引发的异常继承自预期异常,则测试将失败


如果您想遵循AAA模式(排列、动作、断言),则可以这样做,而不管测试框架如何:

[Test]
public void MyMethod_DodgyStuffDone_ThrowsRulesException() {

    // arrange
    var myObject = CreateObject();
    Exception caughtException = null;

    // act
    try {
        myObject.DoDodgyStuff();
    }
    catch (Exception ex) {
        caughtException = ex;
    }

    // assert
    Assert.That(caughtException, Is.Not.Null);
    Assert.That(caughtException, Is.TypeOf<RulesException>());
    Assert.That(caughtException.Message, Is.EqualTo("My Error Message"));
}
[测试]
public void MyMethod_dodgystuff done_throwRulesException(){
//安排
var myObject=CreateObject();
异常caughtException=null;
//表演
试一试{
myObject.DoDodgyStuff();
}
捕获(例外情况除外){
caughtException=ex;
}
//断言
Assert.That(caughtException,Is.Not.Null);
Assert.That(caughtException,Is.TypeOf());
Assert.That(caughtException.Message,Is.EqualTo(“我的错误消息”);
}
您可以使用e Verify()方法进行单元测试,并比较返回类型中的异常消息

InterfaceMockObject.Verify(i =>i.Method(It.IsAny<>())), "Your received Exception Message");
验证(i=>i.Method(It.IsAny()),“您收到的异常消息”);
您需要在其中写入一些类名或数据类型。IsAny block

什么单元测试框架?visual studio附带的标准单元测试系统,我不确定它是否有特定的名称我不喜欢这个答案,因为它使测试通过,即使异常是在您不期望的地方抛出的。@abatishchev如果您(例如)在测试中调用三个不同的方法,该属性只是确保ArgumentException必须在某个地方出现,但也许你想确保ArgumentException只由这三个方法调用中的一个引发。你说过知道你的测试会引发和异常,你想测试一下,对吧?不,你通常想测试一个特定的操作会引发异常。如果其他内容引发异常,则测试不应通过。我也不喜欢将异常类型指定为字符串,而不是使用
typeof(…)
第一种方法并不好,因为它不会在引发异常的代码路径中断言。一个好的测试总是需要断言一些期望发生了。我宁愿在catch块中设置一个标志,或者将异常保存在局部变量中,以便在最后断言。@Brian:断言是隐式的,因为我们没有到达assert.Fail(因此引发了一个异常),并且只捕获了正确的异常(因此不能引发另一个异常)。我对这种风格一点问题都没有——它清楚地表明了IMO的期望值。不过,就紧凑性而言,我更喜欢
Assert.Throws
。请注意,如果您需要检查异常的任何其他详细信息,您可以在catch块中轻松地进行检查。尽管破译不到达assert.Fail()意味着测试通过这一点仍然很简单,但我认为如果在答案中的方法和在catch块之后保存异常并在其上断言的方法之间选择,则可以更清楚地表达测试的意图。归根结底,这是一种风格的选择,也许更重要的是,这是对微软的一次呼吁,要求他们改进assert功能,使其与其他框架竞争。@Brian:这绝对是一种风格的选择-我自己真的不喜欢“保存例外”的方法,但我可以看出它对那些让所有东西都遵循AAA方法的人有多大的吸引力。当然,即使您的框架不支持它,实现
Assert.Throws
也很简单……但不幸的是,如果异常被抛出到方法中的任何地方,而不仅仅是您期望的地方,它就会通过。
InterfaceMockObject.Verify(i =>i.Method(It.IsAny<>())), "Your received Exception Message");