NUnit与Debug.Assert冲突

9
我正在使用NUnit为我的同事编写的库编写单元测试。他的库包含许多在无效输入时触发的Debug.Asserts。当我给他的库提供无效输入时,他的Debug.Asserts会弹出一个消息框,投诉错误的输入。
我认为,当无效输入时,它的库抛出断言是一件好事,但同时我希望单元测试覆盖这些情况。但是,这样做会导致消息框弹出,我必须手动点击OK继续进行剩余的单元测试。
如果不清楚,我的问题是单元测试过程停留在Debug.Assert上。人们应该在任何checkin之前运行他们的单元测试,这应该是自动的,除非测试失败,否则不应该弹出消息。
在这种情况下,“最佳”方法是什么?
3个回答

4

请查看Debug.Assert方法的MSDN文档。具体来说,在“备注”下面,它解释了如何禁用UI:

<configuration>
  <system.diagnostics>
    <assert assertuienabled="false" logfilename="c:\\myFile.log" />
  </system.diagnostics>
</configuration>

因此,我建议应用程序配置文件默认具有此功能,并且您的同事在觉得有用时打开UI断言。

3

正如Henk所指出的那样,抑制UI是无用的,因为你想让你的代码失败。当你不想改变你的代码时,你可以编写一个自定义跟踪侦听器,抛出异常,如下所示:

public class ProductionTraceListener : DefaultTraceListener
{
    public override void Fail(string message, string detailMessage)
    {
        string failMessage = message;

        if (detailMessage != null)
        {
            failMessage += " " + detailMessage;
        }

        throw new AssertionFailedException(failMessage);
    }
}

[Serializable]
public class AssertionFailedException : Exception
{
    public AssertionFailedException() { }
    public AssertionFailedException(string message) : base(message) { }
    public AssertionFailedException(string message, Exception inner) 
        : base(message, inner) { }
    protected AssertionFailedException(SerializationInfo info,
        StreamingContext context) : base(info, context) { }
}

您可以按照以下方式进行注册:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.diagnostics>
    <trace>
      <listeners>
        <clear />
        <add name="Default"
          type="[Namespace].ProductionTraceListener, [Assembly]" />
      </listeners>
    </trace>
  </system.diagnostics>
</configuration>

如你所料,从跟踪侦听器的名称 ProductionTraceListener 可以看出,我在生产环境(Web 应用程序)中使用它,而不是在单元测试中使用。虽然您可以在单元测试中使用此技巧,但我建议您更改代码。在我看来,你应该只为永远不会运行的代码路径使用断言,如果它们确实运行了,则测试应该失败。在您的情况下,当断言失败时您希望有一个成功的测试,这是反直觉的。
我的建议是更改代码并使用常规的 if (x) throw ArgumentException() 检查前提条件(或使用 CuttingEdge.Conditions),并仅将这些断言用于永远不应运行的代码路径。同时,请尝试使用 Trace.Assert 而不是 Debug.Assert,因为您也希望这些断言在生产环境中得到检查。当您完成后,您可以在生产环境中使用 ProductionTraceListener,而在单元测试中使用此 UnitTestTraceListener
public class UnitTestTraceListener : DefaultTraceListener
{
    public override void Fail(string message, string detailMessage)
    {
        string failMessage = message;

        if (detailMessage != null)
        {
            failMessage += " " + detailMessage;
        }

        // Call to Assert method of used unit testing framework.
        Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Fail(
            failMessage);
    }
}

祝你好运。


这对于Trace.Assert()看起来不错,但OP提到了Debug.Assert()。 - H H
此外,您希望代码在作为自动化构建过程的一部分运行时,在单元测试中失败。Asserts 可以让开发人员在运行代码时受益。 - Rob
@Henk && @Rob:我不确定我是否理解你们的意思。在单元测试环境中配置“ProductionTraceListener”将允许单元测试在方法未抛出预期的“AssertionFailedException”时失败。当单元测试以调试模式运行时,这将完全按照他所希望的方式进行,不是吗?请给我指点迷津。 - Steven
Steven,Debug.Assert()不好,因为它使得Debug版本的行为与Release版本不同。你想测试哪种行为? - H H
Henk,这正是我建议使用Trace.Assert的原因。在调试版本中表现不同是一件坏事。我认为我们对此有相同的看法。 - Steven

2

我发现一个简单有效的选项是使用标准的ConsoleTraceListener,它可以使Debug.Assert检查触发,但将它们的输出定向到NUnit文本输出选项卡,而不会影响单元测试。

您可以将此添加到您的测试设置中...

[SetUp]
public void SetUp()
{
    // Replace pop-up assert trace listener with one that simply logs a message.
    Debug.Listeners.Clear();
    Debug.Listeners.Add(new ConsoleTraceListener());
}

当测试失败时,不要忘记检查文本输出!


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