NUnit conflict with Debug.Assert

落爺英雄遲暮 提交于 2019-12-03 12:56:24

Take a look at the MSDN documentation for the Debug.Assert method. Specifically under "Remarks", it explains how you can disable the UI:

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

Therefore I'd suggest that the application config file has this by default and your colleague switches on Assert to UI whenever he feels it useful to do so.

As Henk already noted, suppressing the UI is useless, because you want your that code to fail. When you don't want to change your code, you can write a custom trace listener that throws an exception, as follows:

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) { }
}

And you can register it as follows:

<?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>

As you already might expect from the trace listener's name ProductionTraceListener, I use that thing in my production environment (web applications), and not in my unit tests. While you can use this trick in your unit tests, I advice you to change your code. IMO you should only use asserts for code paths that should never run, and if they do, the test should fail. In your situation you want to have a succeeding test when a assert fails, which is counterintuitive.

My advice is to change the code and use normal if (x) throw ArgumentException() checks for preconditions (or use CuttingEdge.Conditions) and use those asserts only for code paths that should never run. Also try using Trace.Assert instead of Debug.Assert, because you also want those asserts to be checked in your production environment. When you've done that you can use the ProductionTraceListener in your production environment, and this UnitTestTraceListener in your unit tests.

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);
    }
}

Good luck.

A simple option that I find effective is to use the standard ConsoleTraceListener, which will allow the Debug.Assert checks to fire but will direct their output to the NUnit Text Output tab without otherwise influencing the unit test.

You can add this to your test setup ...

[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());
}

Just don't forget to check the text output when a test fails!

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!