NUnit result are different in debug and release

400 views Asked by At

I can't get rid of this problem. It's very strage, when I try to run my NUnit test in Debug mode, I get the expected result but when I just run it normally, the result is Wrong.

What i'm trying to do is detect Binding errors. Here is a sample

[TestFixture, RequiresSTA]
public class BindingTests
{
    [Test]
    public void T1_BindingErrorsExpected()
    {
        string error = null;
        using (var listener = new ObservableTraceListener())
        {
            listener.TraceCatched += s => error = s;

            TextBlock myText = new TextBlock();
            UserControl control = new UserControl();
            Binding myBinding = new Binding("BadBinding");
            myBinding.Source = control;
            myText.SetBinding(TextBlock.BackgroundProperty, myBinding);
        }
        Assert.IsNotNull(error);
    }
}

And the ObservableTraceListener

public sealed class ObservableTraceListener : DefaultTraceListener
{
    private readonly StringBuilder _Builder = new StringBuilder();
    public ObservableTraceListener()
    {
        PresentationTraceListener.Add(SourceLevels.Error, this);
    }

    public new void Dispose()
    {
        Flush();
        Close();
        PresentationTraceListener.Remove(this);
        base.Dispose();
    }   

    public override void Write(string message)
    {
        _Builder.Append(message);
    }

    public override void WriteLine(string message)
    {
        Write(message);

        if (TraceCatched != null)
            TraceCatched(_Builder.ToString());

        _Builder.Clear();
    }

    public event Action<string> TraceCatched;
}


public static class PresentationTraceListener
{
    public static void Add(SourceLevels level, TraceListener trace)
    {
        PresentationTraceSources.DataBindingSource.Listeners.Add(trace);
        PresentationTraceSources.DataBindingSource.Switch.Level = level;
        PresentationTraceSources.ResourceDictionarySource.Listeners.Add(trace);
        PresentationTraceSources.ResourceDictionarySource.Switch.Level = level;
    }

    public static void Remove(TraceListener trace)
    {
        PresentationTraceSources.DataBindingSource.Listeners.Remove(trace);
        PresentationTraceSources.ResourceDictionarySource.Listeners.Remove(trace);
    }
}

Result in debug -> Fail (What I expect)

Result in Run-> Success (Not what expected)

2

There are 2 answers

0
Heyjee On BEST ANSWER

Thanks MatthewMartin but I found the solution looking at https://github.com/bblanchon/WpfBindingErrors

The probem was my ObservableTraceListener.

I needed to add a static constructor calling PresentationTraceSources.Refresh() to get it works correctly. As said in MSDN doc, it Refreshes trace sources, by forcing the app.config file to be re-read. So, some initialization was just done when I started the test in "debug" mode, which probably caused the app.config file to be read.

MSDN doc -> PresentationTraceSources.Refresh() http://msdn.microsoft.com/en-us/library/system.diagnostics.presentationtracesources.refresh%28v=vs.100%29.aspx

Here is my final ObservableTraceListener and the PresentationTraceListener is the same as the one in the question

public sealed class ObservableTraceListener : TraceListener
{
    private readonly StringBuilder _Builder = new StringBuilder();


    static ObservableTraceListener()
    {
        PresentationTraceSources.Refresh();
    }

    public ObservableTraceListener()
    {
        PresentationTraceListener.Add(SourceLevels.Error, this);
    }

    public new void Dispose()
    {
        Flush();
        Close();
        PresentationTraceListener.Remove(this);
        base.Dispose();
    }   

    public override void Write(string message)
    {
        _Builder.Append(message);
    }

    public override void WriteLine(string message)
    {
        _Builder.Append(message);

        if (TraceCatched != null)
            TraceCatched(_Builder.ToString());

        _Builder.Clear();
    }

    public event Action<string> TraceCatched;
}
3
MatthewMartin On

Posting an answer because a comment would be too small to hold what I want to say...

There is no reference to PresentationTraceListener on the internet-- how it treats the TraceListener is important because AFAIK the PresentationTraceListener is what calls the Write/WriteLine methods of the TraceListener (possibly indirectly via TraceSource)

This code below compiles in a brand new project. If I Write(x), I get null, if I writeLine(x), I get a value. Generally when you write a custom TraceListener, you redirect all the overloads to a single method so that they all behave the same (Write and WriteLine should be identical except WriteLine tacks a newline onto the message for the caller.)

Another observation is that System.Diagnostics trace is a quirky logging library whose main advantage is that it is always available even when there is some barrier to using 3rd party libraries. System.Diagnostics trace really wants you to register a TraceSwitch, TraceListener in your app.config or web.config and use that to enable & disable trace. It also requires the the TRACE flag be registered (in the same way the DEBUG flag gets registered, in the project properities-- by default TRACE is defined for DEBUG and RELEASE)

[TestFixture, RequiresSTA]
public class BindingTests
{
    [Test]
    public void T1_BindingErrorsExpected()
    {
        string error = null;
        using (var listener = new ObservableTraceListener())
        {
            listener.TraceCatched += s => error = s;

            //TextBlock myText = new TextBlock();
            //UserControl control = new UserControl();
            //Binding myBinding = new Binding("BadBinding");
            //myBinding.Source = control;
            //myText.SetBinding(TextBlock.BackgroundProperty, myBinding);
            PresentationTraceSources.DataBindingSource.TraceEvent(TraceEventType.Error,0, "Hello World!");    
        }
        Assert.IsNotNull(error);
        Console.WriteLine(error);

    }
}

public sealed class ObservableTraceListener : TraceListener
{
    private readonly StringBuilder _Builder = new StringBuilder();
    public ObservableTraceListener()
    {
        //PresentationTraceListener.Add(SourceLevels.Error, this);
    }
    protected override void Dispose(bool disposing)
    {
        Flush();
        Close();
        //PresentationTraceListener.Remove(this);
    }

    public override void Write(string message)
    {
        _Builder.Append(message);
    }

    public override void WriteLine(string message)
    {
        Write(message);

        if (TraceCatched != null)
            TraceCatched(_Builder.ToString());

        _Builder.Clear();
    }

    public event Action<string> TraceCatched;
}