WPF验证调用不是从GUI线程进行的

时间:2013-12-09 16:56:54

标签: c# wpf multithreading unit-testing nunit

我在上周尝试过其他SO问题的各种方法,这是我发现的最佳方法,但我不知道如何用NUnit进行单元测试。

private void VerifyDispatcherThread()
    {
        var context = SynchronizationContext.Current;

        if (context != null && context is DispatcherSynchronizationContext)
        {
            Log.For(this).Info("WARNING! - Method Should Not Be Called From Dispatcher Thread.");

            if (DispatcherThreadSafetyEnabled)
            {
                throw new ThreadStateException("Method Should Not Be Called From Dispatcher Thread.");
            }
        }
    }

这是我们的测试(不工作)

        [Test]
        public void Should_throw_exception_when_called_from_dispatcher()
        {
            // Arrange
            var called = false;
            Boolean? success = null;

            var httpClient = new HttpClient(HttpTimeOut);

            // This emulates WPF dispatcher thread
            SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext());

            Dispatcher dispatcher = Dispatcher.CurrentDispatcher;

            // Act
            dispatcher.BeginInvoke(delegate()
            {
                try
                {
                    ConfigurationManager.AppSettings.Set("DispatcherThreadSafetyEnabled", "true");
                    httpClient.Post("http://Foo", "content xml");
                    success = true;
                }
                catch
                {
                    success = false;
                }
                finally
                {
                    ConfigurationManager.AppSettings.Set("DispatcherThreadSafetyEnabled", "false");
                }
                called = true;
            });

            // this part is a bit ugly
            // spinlock for a bit to give the other thread a chance
            var timeout = 0;
            while (!called && timeout++ < 1000)
                Thread.Sleep(1);

            // Assert
            Assert.IsNotNull(success, "Method was never invoked");
            Assert.IsFalse(success.Value, "Expected to fail");
        }

DispatcherThreadSafetyEnabled是我们的app.config设置,因此我们只能切换日志记录或抛出异常。

我们要做的是验证调用方法在调用时不使用GUI线程。它似乎正在工作,但我们正在努力进行单元测试。

这里希望有人这样做,可以帮助我们应对挑战。

1 个答案:

答案 0 :(得分:1)

当前 SynchronizationContext由不同的框架(Winforms,WPF等)设置为不同的实现。

引自this MSDN文章:

  

WindowsFormsSynchronizationContext(System.Windows.Forms.dll:   System.Windows.Forms)Windows窗体应用程序将创建并安装一个   WindowsFormsSynchronizationContext作为任何的当前上下文   创建UI控件的线程。

     

DispatcherSynchronizationContext(WindowsBase.dll:   System.Windows.Threading)WPF和Silverlight应用程序使用   DispatcherSynchronizationContext,将委托排队到UI   thread的Dispatcher具有“Normal”优先级。这个   当a时,SynchronizationContext作为当前上下文安装   线程通过调用Dispatcher.Run开始其Dispatcher循环。

由于您只测试非空和SynchronizationContext的类型,请尝试通过从单元测试中调用SynchronizationContext将当前DispatcherSynchronizationContext设置为SynchronizationContext.SetSynchronizationContext的实例。示例代码如下:

SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher));

请注意,这不是Winforms / WPF应用程序中推荐的。