【问题标题】:NUnit result are different in debug and releaseNUnit 结果在调试和发布时不同
【发布时间】:2015-01-24 02:15:55
【问题描述】:

我无法摆脱这个问题。这很奇怪,当我尝试在 Debug 模式下运行我的 NUnit 测试时,我得到了预期的结果,但是当我正常运行它时,结果是错误的。

我想要做的是检测绑定错误。这是一个示例

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

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

调试结果 -> 失败(我所期望的)

运行结果-> 成功(不是预期的)

【问题讨论】:

  • 我猜这与 DefaultTraceListener 的副作用有关,它试图调用旧式跟踪机制 (OutputDebugString)。使用它作为基类而不是从 TraceListener 派生的动机是什么?
  • 没有具体原因。明天我会尝试实现traceListener,我会给你反馈
  • 我刚刚用public sealed class ObservableTraceListener : TraceListener而不是public sealed class ObservableTraceListener : DefaultTraceListener进行了测试,并没有解决问题。
  • 我刚刚更新了我的示例,当我处于调试模式时,myText.SetBinding() 会引发对 TraceListner 的调用。在运行模式下,setBinding 方法不会抛出。如果这可以帮助...

标签: c# unit-testing binding nunit tracelistener


【解决方案1】:

感谢 MatthewMartin,但我在 https://github.com/bblanchon/WpfBindingErrors 找到了解决方案

探针是我的ObservableTraceListener

我需要添加一个调用PresentationTraceSources.Refresh() 的静态构造函数以使其正常工作。正如 MSDN 文档中所说,它是Refreshes trace sources, by forcing the app.config file to be re-read。所以,当我在“调试”模式下开始测试时,刚刚完成了一些初始化,这可能导致 app.config 文件被读取。

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

这是我的最终ObservableTraceListenerPresentationTraceListener 与问题中的相同

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

【讨论】:

    【解决方案2】:

    发布答案是因为评论太小而无法容纳我想说的话...

    互联网上没有提到 PresentationTraceListener - 它如何处理 TraceListener 很重要,因为 AFAIK PresentationTraceListener 是调用 TraceListener 的 Write/WriteLine 方法(可能间接通过 TraceSource)

    下面的代码在一个全新的项目中编译。如果我写(x),我得到空值,如果我写线(x),我得到一个值。通常,当您编写自定义 TraceListener 时,您会将所有重载重定向到单个方法,以便它们的行为都相同(Write 和 WriteLine 应该相同,除了 WriteLine 在调用者的消息上添加换行符。)

    另一个观察结果是 System.Diagnostics 跟踪是一个古怪的日志库,其主要优点是它始终可用,即使在使用 3rd 方库存在一些障碍时也是如此。 System.Diagnostics 跟踪确实希望您在 app.config 或 web.config 中注册 TraceSwitch、TraceListener 并使用它来启用和禁用跟踪。它还需要注册 TRACE 标志(与在项目属性中注册 DEBUG 标志的方式相同——默认情况下,TRACE 是为 DEBUG 和 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;
    }
    

    【讨论】:

    • 很抱歉 PresentationTraceListener 是我的自定义类。我编辑我的帖子
    • 好的,PresentationTraceSources.DataBindingSource 是一个普通的 TraceSource,直接调用时效果很好,无论是在我的机器上的 DEBUG 还是 RELEASE 中。我确实注意到“错误”只包含最新的值,所以如果 Binding()、.Source、.SetBinding() 都写入 TraceSource(包括可能的空行),您可能看不到您期望的消息。)另外,尝试在 Verbose 级别记录,也许它在发布模式下被记录为警告。我的下一步是反汇编那个 Binding 对象,看看它是如何调用 TraceSource 的。
    • 谢谢,但我找到了解决方案并发布了它!我知道错误只是保留最后一个绑定错误,但这只是一个简化的示例!在我的项目中,我使用带有 append() 方法的 stringBuilder 来保存所有绑定错误,并且我使用 Assert.That(sb.ToString(), Is.Empty, sb.ToString()) ...如果这可以帮助某人!
    猜你喜欢
    • 2020-01-15
    • 1970-01-01
    • 2011-09-19
    • 1970-01-01
    • 2016-05-14
    • 1970-01-01
    • 2016-10-31
    • 2020-06-04
    • 2023-04-11
    相关资源
    最近更新 更多