单元测试是否已捕获异常

时间:2012-04-02 09:44:24

标签: c# .net unit-testing task

我有一个需要try / catch的方法。这是因为该方法是从Task调用的。如果抛出异常,则线程将结束。我可以使用Task.ContinueWith来处理错误,然后在发生错误的情况下启动一个新任务,但是try / catch可以解决这个问题。

无论如何,我知道我需要放一个try / catch但是如何测试异常被捕获?

我可以做的一种方法是引发一个接受字符串参数的现有事件,然后在单元测试中测试该字符串是否匹配我期望的字符串。不确定这是好还是不好但是想知道处理这种情况的最佳方法是什么。

4 个答案:

答案 0 :(得分:3)

如果您正在进行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块的类都按预期工作,并且您的组件按预期工作,在应该的时候引发异常。

答案 1 :(得分:1)

你添加一个try / catch意味着当被测试的类调用另一个抛出异常时你有所需的行为。 try / catch是“如何”,测试行为。

因此,使用模拟,在调用“其他”服务时抛出异常,并测试您的类是否满足要求。首先编写测试,这将使您想到为什么要放入try / catch。

答案 2 :(得分:1)

您应该测试应用程序实际正在执行的 ,而不是如何。因此,只需模拟您的任务以抛出异常,并验证在这种情况下是否引发了新任务。

答案 3 :(得分:0)

这就是我所追求的,但会对人们的意见感兴趣:

[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();
    }
}