【发布时间】:2011-04-12 09:24:14
【问题描述】:
我正在处理一个项目,我需要与吞下异常的代码进行互操作。特别是,我正在编写 NUnit 单元测试。在某些地方,我想在作为委托传递的代码中嵌入断言,作为模拟特定行为的一部分。我遇到的问题是 AssertionException 被调用委托的代码吞噬,这意味着测试通过,即使测试断言失败。
有什么方法可以通知 NUnit 一个测试应该失败并且不能通过捕获 AssertionException 来规避?我无法修改吞下异常的代码,因为我没有完全的所有权并且它已经在半生产中使用。我希望有一个干净的方法来完成这个。
我想出的最好的是这样的:
private static string _assertionFailure;
public static void AssertWrapper(Action action)
{
try
{
action();
}
catch (AssertionException ex)
{
_assertionFailure = ex.Message;
throw;
}
}
[Test]
[ExpectedException(typeof(AssertionException))]
public void TestDefeatSwallowing()
{
Action failure = () => AssertWrapper(() => Assert.Fail("This is a failure"));
EvilSwallowingMethod(failure);
if (_assertionFailure != null)
Assert.Fail(_assertionFailure);
}
private void EvilSwallowingMethod(Action action)
{
try
{
action();
}
catch
{
}
}
它有效,但它很丑陋。我必须包装每个 Assert 调用,并且必须在每个测试结束时检查断言是否被吞下。
【问题讨论】:
-
不完全相关 - 你是否推动了这段代码吞下异常链的事实?半生产代码应该更容易更改(当然取决于具体情况)。相关 - 这看起来是一种非常聪明的方法。你必须解决一个极其丑陋的模式——这很难干净地做到。
-
@arootbeer,我正在与之合作的团队意识到这是一个问题,但这是一个非常系统性的问题,并且与最终用户认为“崩溃”是最糟糕的事情有关系统可以做到。有人开玩笑地建议可以将代码更改为仅在晚上 7 点到早上 7 点之间吞下异常。
-
哇 - 那我就不说了 :) 你测试的所有方法都接受一个动作作为参数吗?
-
我同意@arootbeer - 解决这个问题(并解决它)不会变得更容易。当它在生产中吞下一个 IOException 并且没有任何东西被保存时会发生什么?放入一个全局异常处理程序,记录详细信息并为用户提供友好的对话。另外,考虑用异常断言替换 ExpectedExceptionAttribute:nunit.org/index.php?p=exceptionAsserts&r=2.5.7
-
@arootbeer,它比我给出的示例稍微复杂一些。断言嵌入在模拟接口调用的回调中,因为我试图感知我正在测试的代码何时调用特定服务以及它是否正确使用服务调用。这相当于传入一个接口的测试实现,在其方法中带有测试断言。是使用服务的代码吞下异常,包括 AssertionException。
标签: c# unit-testing exception nunit assert