【发布时间】:2014-08-14 13:33:05
【问题描述】:
我正在使用 Nunit 进行单元测试,我需要对抛出异常的代码进行单元测试。我的代码与此类似。
public class Myclass
{
public int Count
{
get; set;
}
public void Foo()
{
try
{
if (Count >3)
{
throw new Exception();
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
}
[TestFixture]
public class TestMyClass
{
[Test]
public void TestFoo()
{
var obj = new Myclass();
obj.Count = 4;
Assert.Throws<Exception>(obj.Foo);
}
}
这会产生这样的错误
Expected: <System.Exception>
But was: null
我发现如果我删除 try catch 块,单元测试通过。但我不想更改实际代码。请告知我如何对上述代码进行单元测试以及正确的做法。
【问题讨论】:
-
对于初学者来说,您不应该在要进行单元测试的代码中包含消息框(或任何其他 gui 代码)。另请注意,您的代码有效地吞下了异常。它将它显示为一个消息框,但它不会重新抛出它,因此您的单元测试将永远不会看到它。简而言之,您需要更改实际代码,因为它不是为了测试而编写的。而no,这里的正确方法是不去弄清楚如何测试是否显示了消息框。这里正确的做法是重构代码,将GUI代码与其背后的逻辑分开。
-
@LasseV.Karlsen 感谢您的建议。我也认为这可能是原因,但是如果我注释掉消息框行并且只有一个空的 catch 块,它仍然会失败并给出相同的错误。我愿意不明白其中的原因。
-
空的 catch 块捕获异常但不重新抛出它。你基本上是在说“我会接受这个例外并忽略它”。简而言之,不要那样做。在 catch 块中添加
throw;行,您的单元测试应该会看到异常,但如果这就是 try/catch 所做的一切,您应该将其删除。同样,您不应该在通过单元测试执行的代码中包含 GUI 代码。 -
如果您需要将 GUI 响应输出到其他代码,您应该找到一种不同的方法来完成。通过返回保证消息框的结果,但该消息框由调用您的函数的 GUI 代码处理,或者将对象注入可用于引发事件的对象/方法中,您的 GUI 代码将显示一个消息框来响应。
-
请注意,错误处理不是一个可以掉以轻心的主题。如果在向最终用户显示异常后重新抛出异常,它可能最终会被 .NET 运行时捕获,该运行时会将其作为未捕获的异常处理,并可能终止您的程序。如果您希望您的逻辑以可以测试它是否被抛出的方式抛出异常,则不应使用其中的消息框,也不要捕获它(至少不要吞下它)。然后,在 GUI 代码中,您将对方法的调用包装在 try/catch 中。
标签: c# unit-testing exception nunit