10

I have this property:

    public SubjectStatus Status
    {
        get { return status; }
        set
        {
            if (Enum.IsDefined(typeof(SubjectStatus), value))
            {
                status = value;
            }
            else
            {
                Debug.Fail("Error setting Subject.Status", "There is no SubjectStatus enum constant defined for that value.");
                return;
            }
        }
    }

and this unit test

    [Test]
    public void StatusProperty_StatusAssignedValueWithoutEnumDefinition_StatusUnchanged()
    {
        Subject subject = new TestSubjectImp("1");

        //  assigned by casting from an int to a defined value
        subject.Status = (SubjectStatus)2;
        Assert.AreEqual(SubjectStatus.Completed, subject.Status);            

        //  assigned by casting from an int to an undefined value
        subject.Status = (SubjectStatus)100;
        //  no change to previous value
        Assert.AreEqual(SubjectStatus.Completed, subject.Status);            
    }

Is there a way I can prevent Debug.Fail displaying a message box when I run my tests, but allow it to show me one when I debug my application?

Grokodile
  • 3,881
  • 5
  • 33
  • 59

3 Answers3

10

An alternative way that doesn't require changing your production code or writing a custom NUnit add-in, would be to replace the trace listeners in a setup fixture.

E.g. Add the following class inside the namespace your tests are in:

using System;
using System.Diagnostics;
using NUnit.Framework;

[SetUpFixture]
public class NUnitSetup
{
    // Field to hold exisitng trace listeners so they can be restored after test are run.
    private TraceListener[] originalListeners = null;

    // A trace listener to use during testing.
    private TraceListener nunitListener = new NUnitListener();

    [SetUp]
    public void SetUp()
    {
        // Replace existing listeners with listener for testing.
        this.originalListeners = new TraceListener[Trace.Listeners.Count];
        Trace.Listeners.CopyTo(this.originalListeners, 0);
        Trace.Listeners.Clear();
        Trace.Listeners.Add(this.nunitListener);
    }

    [TearDown]
    public void TearDown()
    {
        // Restore original trace listeners.
        Trace.Listeners.Remove(this.nunitListener);
        Trace.Listeners.AddRange(this.originalListeners);
    }

    public class NUnitListener : DefaultTraceListener
    {
        public override void Fail(string message)
        {
            Console.WriteLine("Ignoring Debug.Fail(\"{0}\")", message);
        }

        public override void Fail(string message, string detailMessage)
        {
            Console.WriteLine("Ignoring Debug.Fail(\"{0},{1}\")", message, detailMessage);
        }
    }
}
Ergwun
  • 12,579
  • 7
  • 56
  • 83
  • 1
    You don't even need a custom trace listener, just install the ConsoleTraceListener. Then all your Debug.Assert/Fail messages go to the NUnit text output tab, without otherwise affecting the tests. – yoyo Jun 11 '14 at 23:15
  • Update for NUnit 3.0: [SetupFixture] conflicts with [SetUp] and [TearDown]. But that's okay -- just insert the whole class, without the initial [SetUpFixture], inside your TextFixture. Better yet, change [SetUp] to [OneTimeSetUp] (likewise for TearDown) and it will only make the replacement once! This works real sweet! – shipr May 13 '16 at 17:13
2

The standard way I've always done this is to create a plugin for NUnit. The plugin simply unregisters the default trace listener and registers a replacement that throws an exception when Assert/Trace.Fail is triggered. I like this approach because tests will still fail if a assert trips, you don't get any message boxes popping up and you don't have to modify your production code.

Edit -- here's the plugin code in its entirety. You're on your own for building the actual plugin though -- check the NUnit site :)

[NUnitAddin]
public class NUnitAssertionHandler : IAddin
{
    public bool Install(IExtensionHost host)
    {
        Debug.Listeners.Clear();
        Debug.Listeners.Add(new AssertFailTraceListener());
        return true;
    }

    private class AssertFailTraceListener : DefaultTraceListener
    {
        public override void Fail(string message, string detailMessage)
        {
            Assert.Fail("Assertion failure: " + message);
        }

        public override void Fail(string message)
        {
            Assert.Fail("Assertion failure: " + message);
        }
    }
}
Mark Simpson
  • 23,245
  • 2
  • 44
  • 44
  • It's not too bad, there's a few things you have to do involving setting files to copy local = false and some other quirks, but I don't have the project here in front of me right now so I can't post the exact steps. It's literally a plugin .dll with one class in it, though :) – Mark Simpson May 09 '10 at 23:25
0

Instead of calling Debug.Assert directly, you could call a wrapper method that checks whether a debugger is attached before invoking Debug.Assert. (Presumably, it should throw an exception if there is no debugger attached so that your tests will fail.) e.g.:

[Conditional("DEBUG")] 
public static void Assert(bool condition) 
{ 
    if (Debugger.IsAttached) 
    { 
        Debug.Assert(condition); 
    } 
    else 
    { 
        throw new SomeException(); 
    } 
}
Nicole Calinoiu
  • 20,843
  • 2
  • 44
  • 49