我想断言在某个类中抛出了一个异常

本文关键字:异常 一个 断言 | 更新日期: 2023-09-27 18:24:13

我正在为我的客户端/服务器设置构建一个TestProject。我想验证测试在某个执行块内是否失败(没有客户端可发送,因此服务器的send()方法将抛出异常)。由于我不想让测试启动客户端和服务器,并让它们进行通信(我在一台机器上遇到了问题)

如果代码到达这一行,这意味着程序的执行流只能在另一个测试的职责范围内失败。除了对抛出异常的堆栈进行子字符串检查之外,还有什么更简单的方法可以做到这一点吗?我觉得这个方法不是很容易扩展,如果类名发生变化,就需要经常关注。

有没有一种方法甚至不需要手动检查异常的堆栈竞争?

我想断言在某个类中抛出了一个异常

如果您使用NUnit

不使用DataAnnotations

[Test]
public void Test_XXXXXXX
{
    var yourClass = new YourClass(); 
    Assert.That(()=>yourClass.Method(),
                    .Throws.Exception
                    .TypeOf<TypeOfYourException>
                    .With.Property("Message")
                    .EqualTo("the message you are expecting goes here")
               );
}

使用DataAnnotations

[Test]
[ExpectedException(typeof(ExceptionType), ExpectedMessage="your message goes here!")]
public void Test_XXXXXXX
{
      var yourClass = new YourClass();     
      // Call your method in a way that it will fail
      yourClass.YourMethod();
}

除了特定于该类之外,类中的异常还有什么独特之处吗?

如果消息可以识别它,你可以按照其他答案进行测试,或者如果你没有使用NUnit:

try {    
   myMethod();
   Assert.Fail("Expected exception to be thrown."); 
} catch (MyException ex) {    
   Assert.Equals("My Exception Message", ex.Message, "Exception message was formatted incorrectly.");
} catch (Exception) {    
   Assert.Fail("An exception was thrown, but of the wrong type.");    
}

当您对某个类进行单元测试时,有两个异常源:

  1. 正在测试的类可能引发异常
  2. 类的依赖项可能引发异常

在第二种情况下,您通常要么处理异常,要么将其封装在更高级的异常中并将其抛出给调用者。那么,如何测试所有这些案例呢?

测试中的系统抛出异常

例如,在传递给方法(NUnit示例)的参数错误的情况下抛出异常:

StockService service = new StockService();
Assert.Throws<ArgumentNullException>(() => service.Connect(null));

您不需要检查堆栈跟踪,因为它是一个被测试的类,应该抛出异常。

依赖抛出异常,我们处理它

当你的类有依赖关系时,你应该模拟依赖关系,以便孤立地测试你的类。因此,当您的类与mock交互时,设置mock抛出异常是非常容易的。如果找不到配置文件(Moq示例),则考虑服务应在默认设置下运行的情况:

var configMock = new Mock<IStockServiceConfig>();
configMock.Setup(c => c.Load()).Throws<FileNotFoundException>();
StockService service = new StockService(configMock.Object);
service.Connect("google");
configMock.VerifyAll();
Assert.That(service.Port, Is.EqualTo(80));

如果不尝试加载配置,或者不处理FileNotFoundException,则此测试将失败。

异常堆栈竞争在这里并不重要——我们不在乎我们的直接依赖是否抛出了异常,或者它是依赖中的其他类实际上,我们不知道这个类是否存在-我们只使用直接依赖关系进行交互。我们应该只关心这样一个事实,即依赖可以抛出异常,我们可以处理它。

依赖抛出异常,我们将其包装

最后一个案例——用更高级的东西包装异常。请考虑前面的示例,但配置非常重要,并且您不能在没有配置文件的情况下启动。在这种情况下,您可以将FileNotFoundException封装到更具体的业务中,这在应用程序的更高级别上是有意义的。例如StockServiceInitializationException:

var configMock = new Mock<IStockServiceConfig>();
configMock.Setup(c => c.Load()).Throws<FileNotFoundException>();
StockService service = new StockService(configMock.Object);
Assert.Throws<StockServiceInitializationException>(_ => service.Connect("bing"));
configMock.VerifyAll();

正如您所看到的,我们也不关心异常的堆栈争用,这会抛出我们的依赖关系。它也可能是一些更低级异常的包装器。如果找不到配置,则服务的预期行为将引发高级初始化异常。我们正在这里验证这种行为。