单元测试是否捕捉到异常
本文关键字:异常 是否 单元测试 | 更新日期: 2023-09-27 18:29:40
我有一个方法需要一个try/catch。这是因为该方法是从Task
调用的。如果抛出异常,线程将结束。我可以使用Task.ContinueWith
来处理错误,然后在出现错误时启动一个新任务,但try/catch就可以了。
无论如何,我知道我需要放入一个try/catch,但我该如何测试异常是否被捕获?
我可以做的一种方法是引发一个接受字符串参数的现有事件,然后在单元测试中,测试这个字符串是否与我期望的字符串匹配。不确定这是好是坏,但想知道处理这种情况的最佳方法是什么
如果你在做TDD,你应该循序渐进,专注于你的类应该做什么。您想打印一些报告。首先(我想你是搬进来的),你设计类Report
,它应该通过Printer
打印自己(这只是一个例子)。所以你写测试:
[Test]
public void ShouldPrintItself()
{
Mock<IPrinter> printer = new Mock<IPrinter>();
Report report = new Report(printer.Object);
report.Text = "foo";
report.Print();
printer.Verify(p => p.Print("foo"));
}
并为report.Print
方法编写了一些实现。此外,您现在正在设计IPrinter接口。接下来你会明白,打印机有时会显示异常(例如缺纸)。顺便说一下,这是您的情况。因此,您将report.Print
方法重命名为类似TryPrint
的方法,更改第一个测试并创建新的测试:
[Test]
public void ShouldPrint()
{
Mock<IPrinter> printer = new Mock<IPrinter>();
Report report = new Report(printer.Object);
report.Text = "foo";
Assert.True(report.TryPrint());
printer.Verify(p => p.Print("foo"));
}
[Test]
public void ShouldNotPrint()
{
Mock<IPrinter> printer = new Mock<IPrinter>();
printer.Setup(p => p.Print(It.IsAny<string>())).Throws<Exception>();
Report report = new Report(printer.Object);
report.Text = "foo";
Assert.False(report.TryPrint());
}
然后返回到TryPrint
方法。现在,您将try catch
块围绕调用添加到打印机,并使测试通过(和您在应用程序中应该做的一样):
public bool TryPrint()
{
try
{
_printer.Print(_text);
return true;
}
catch (Exception ex)
{
// of course, log exception
return false;
}
}
完成此操作后,可以转到Printer
创建。在您的情况下,它将是组件测试。好消息-您已经设计好了IPrinter
接口。因此,您编写测试并验证在某些情况下会抛出异常:
[Test]
public void ShouldThrowExceptionWhenNoPaperLeft()
{
Printer printer = new Printer();
printer.PagesCount = 0;
Exception ex = Assert.Throws<Exception>(() => printer.Print("foo"));
Assert.That(ex.Message, Is.EqualTo("Out of paper"));
}
当然,您编写组件实现是为了通过此测试。之后,具有try catch
块的类和组件都按预期工作,在应该时引发异常。
添加try/catch意味着当被测试的类调用另一个抛出异常的类时,您具有所需的行为。try/catch是"如何",测试行为。
因此,使用mocking,在调用"其他"服务时抛出异常,并测试您的类是否完成了所需的操作。首先编写测试,这会让你思考为什么要放入try/catch。
您应该测试您的应用程序实际在做什么,而不是如何。所以,只需模拟您的任务以抛出异常,并验证在这种情况下是否引发了新任务。
这是我所做的,但会对人们的意见感兴趣:
[Test]
public void DoSomething_NullParameterEntered_ShouldCatchException()
{
var component = new Whatever();
try
{
component.DoSomething(null); //If a try/catch block exists it will not fall into the below catch
}
catch
{
Assert.Fail();
}
}