单元测试是否捕捉到异常

本文关键字:异常 是否 单元测试 | 更新日期: 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();
    }
}