单元测试MVVMLight DispatcherHelper with Timer不起作用

时间:2016-04-18 20:34:29

标签: c# multithreading unit-testing timer mvvm-light

我有一个使用System.Threading.Timer的应用程序。当调用Timer回调时,我必须在UI线程上做一些事情。我使用MVVMLight DispatcherHelper来做到这一点。它在我运行应用程序时工作正常,但是当我对它进行单元测试时(使用nUnit),DispatcherHelper不会调用Action。

为了演示它,我创建了一个简单的单元测试

Timer _Timer; //this is System.Threading.Timer
bool _DispatcherWorks;

[Test]
public async Task MVVMDispatcherTest()
{
     DispatcherHelper.Initialize();
     Assert.That(DispatcherHelper.UIDispatcher, Is.Not.Null);

     _Timer = new Timer(timerCallback, null, 500, 500); //start timer in 0.5 seconds and run every 0.5 seconds

     Thread.Sleep(2000); //wait for timer to tick

     Assert.That(_DispatcherWorks, Is.True); //will fail
}

private void timerCallback(object state)
{
     Console.WriteLine("Timer tick");
     Assert.That(DispatcherHelper.UIDispatcher, Is.Not.Null);
     DispatcherHelper.CheckBeginInvokeOnUI(() =>
     {
         _DispatcherWorks = true; //this is never called
     });
 }

我的计时器被执行3次,这是预期的。但DispatcherHelper.CheckBeginInvoikeOnUI中的Action不会被调用。任何人都可以建议为什么这不起作用以及如何使这个可测试?

2 个答案:

答案 0 :(得分:0)

您的_Timer是System.Threading.Timer的一个实例(调用此实例timerA)。在Dispatchhelper中,创建了一个新的System.Threading.Timer实例(调用该实例timerB)。这可以解释为什么你的测试不起作用。 为了使这个可测试,你可以做一些事情。您可以在Dispatch-helper中注入计时器,但您必须更改生产代码以适应测试。如果可以帮助我,我通常会反对。

您还可以使用Microsoft Fakes来模拟System.Threading.Timer。这是我要采取的方法。

答案 1 :(得分:0)

感谢您的建议,但这对我不起作用,因为我实际上想要测试计时器事件过去时发生的事情。所以我在这里做了什么。

  1. 我从MVVMLight DispatcherHelper.cs获取源代码,将此类从静态类转换为非静态类,并从中提取接口。我将Dispatcher作为参数传递给构造函数。在我的ViewModelLocator中,我启动了新的DispatcherHelper类。
  2. 我将在ViewModelLocator中启动的相同DispatcherHelper对象传递给我需要Dispatcher的每个ViewModel的构造函数。然后我在计时器已用事件中使用此对象。
  3. 在我的单元测试中,我使用nSubstitute来模拟IDispatcherHelper接口并重新定义CheckBeginInvokeOnUI方法以简单地执行传递的操作而不是使用Dispatcher。
  4. 现在,当我测试我的ViewModel时,我将这个模拟的DispatcherHelper传递给ViewModel构造函数,我能够测试计时器内发生的事情。