在NUnit 3中使用[TestCase]属性进行异常测试?

46

如何在使用NUnit3的测试用例中测试异常?

假设我有一个定义如下的方法Divide(a,b):

public double Divide(double a, double b)
{
    if(Math.Abs(b) < double.Epsilon) throw new ArgumentException("Divider cannot be 0");
    return a/b;
}

我想使用NUnit 3.0测试用例来测试此方法,因此可能会有:

[TestCase(-10, 2, -5)]
[TestCase(-1, 2, -0.5)]
public void TestDivide(double a, double b, double result)
{
    Assert.That(_uut.Divide(a, b), Is.EqualTo(result));
}

有没有一种方法可以指定一个测试用例,使Divide()抛出ArgumentException异常,并以某种方式将其作为预期结果,例如:

[TestCase(-10, 2, -5)]
[TestCase(-1, 2, -0.5)]
[TestCase(-1, 0, ExpectedResult = TypeOf(ArgumentException)]
public void TestDivide(double a, double b, double result)
{
    Assert.That(_uut.Divide(a, b), Is.EqualTo(result));
}

当然,我可以定义一个单独的测试方法,并在其中使用Assert.Throws(),所以这纯属出于好奇心。

2个回答

46

ExpectedException是NUnit 2.X中正确的方法,但在NUnit 3中被移除了。

NUnit Google Group和等效的Dev组中有大量关于此问题的讨论片段 - 但看起来决定是,在单独的方法中测试预期结果和异常通常是更好的设计模式。(参见链接)

在NUnit 3中唯一的方法是将其分解为两个单独的测试。(在类似的问题中由NUnit核心团队回答的这里得到确认。)

[TestCase(-10, 2, -5)]
[TestCase(-1, 2, -0.5)]
public void TestDivide(double a, double b, double result)
{
    Assert.That(_uut.Divide(a, b), Is.EqualTo(result));
}

[TestCase(-1, 0)]
public void TestDivideThrows(double a, double b)
{
    Assert.That(() => _uut.Divide(a, b), Throws.TypeOf<ArgumentException>());
}

1
如果你真的想把这两个测试合并成一个,你可以添加一个布尔类型的throwsException参数并进行测试。然而,if-then-else语句的存在和两个完全不同的期望结果证明了这实际上应该是两个不同的测试。 - Charlie
7
“通常更好的设计模式是在单独的方法中测试预期结果和异常情况”。由于“通常更好的设计模式”,我无法在代码中更新nunit框架,这需要重构1000多个测试。这很难以仅仅为了辩解打破变更。 - Marcos Brigante

9

我同意Corpus Gigantus的回答,但为什么不像这样简化:

[TestCase(-10, 2, -5)]
[TestCase(-1, 2, -0.5)]
[TestCase(-1, 0, null, typeof(ArgumentException))]
public void TestDivide(double a, double b, double result, Type exception = null)
{
    if(exception != null)
    {
        Assert.Throws(exception, delegate { _uut.Divide(a, b);  });
                
    } else Assert.That(_uut.Divide(a, b), Is.EqualTo(result));
}

通过这种方式,期望的异常也是测试参数的一部分。请注意,您只能有两种结果,要么是除法成功,要么是抛出异常。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接