如果你正在进行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)
{
return false;
}
}
当你完成这里的操作后,可以开始创建打印机
。在你的情况下,这将是组件测试。好消息是 - 你已经设计了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
块的类按预期工作,并且您的组件按预期工作,在应该引发异常时引发异常。
Catch
块未处理异常,则单元测试将无论如何失败,抛出特定异常,但如果它被捕获/处理,则测试将通过。不确定是否有任何特定的解决方法。 - Rahul