5

我是 C# 和 NUnit 的新手。

在 Boost.Test 中有一系列BOOST_*_THROW宏。在 Python 的测试模块中有TestCase.assertRaises方法。

据我了解,在带有 NUnit(2.4.8)的 C# 中,进行异常测试的唯一方法是使用ExpectedExceptionAttribute.

为什么我更喜欢ExpectedExceptionAttribute——比如说——Boost.Test 的方法?这个设计决策背后的原因是什么?为什么在 C# 和 NUnit 的情况下会更好?

最后,如果我决定使用ExpectedExceptionAttribute,在引发和捕获异常后如何进行一些额外的测试?假设我想测试要求,说对象在一些 setter raise 之后必须是有效的System.IndexOutOfRangeException。您将如何修复以下代码以按预期编译和工作?

[Test]
public void TestSetterException()
{
    Sth.SomeClass obj = new SomeClass();

    // Following statement won't compile.
    Assert.Raises( "System.IndexOutOfRangeException",
                   obj.SetValueAt( -1, "foo" ) );

    Assert.IsTrue( obj.IsValid() );
}

编辑:感谢您的回答。今天,我发现了一个It's the Tests 博客条目,其中提到了您描述的所有三种方法(以及一个较小的变化)。很遗憾我之前找不到它:-(。

4

5 回答 5

13

我很惊讶我还没有看到这种模式。David Arno 非常相似,但我更喜欢这种简单性:

try
{
    obj.SetValueAt(-1, "foo");
    Assert.Fail("Expected exception");
}
catch (IndexOutOfRangeException)
{
    // Expected
}
Assert.IsTrue(obj.IsValid());
于 2008-11-02T23:03:12.757 回答
10

如果您可以使用 NUnit 2.5,那里有一些不错的帮手

Assert.That( delegate { ... }, Throws.Exception<ArgumentException>())
于 2008-11-02T22:55:18.747 回答
4

MbUnit 语法是

Assert.Throws<IndexOutOfRangeException>(delegate {
    int[] nums = new int[] { 0, 1, 2 };
    nums[3] = 3;
});
于 2008-11-02T23:01:01.857 回答
2

我一直采用以下方法:

bool success = true;
try {
    obj.SetValueAt(-1, "foo");
} catch () {
    success = false;
}

assert.IsFalse(success);

...
于 2008-11-02T22:55:41.303 回答
2

您的首选语法:

Assert.Raises( "System.IndexOutOfRangeException",
               obj.SetValueAt( -1, "foo" ) );

无论如何都不能使用 C# - obj.SetValueAt 将被评估并将结果传递给 Assert.Raises。如果 SetValue 抛出异常,那么您永远不会进入 Assert.Raises。

您可以编写一个辅助方法来做到这一点:

void Raises<T>(Action action) where T:Exception {
   try {
      action();
      throw new ExpectedException(typeof(T));
   catch (Exception ex) {
      if (ex.GetType() != typeof(T)) {
         throw;
      }
   }
}

这允许类似的语法:

Assert.Raises<System.IndexOutOfRangeException>(() => 
  obj.SetValueAt(-1, "foo")
;
于 2008-11-02T23:44:20.957 回答