MVVM light Dispatcher单元测试

时间:2016-08-17 08:40:56

标签: c# wpf unit-testing mvvm mvvm-light

我有以下功能

 public void Reset()
 {
     DisableModule();
     DispatcherHelper.UIDispatcher.Invoke(() =>
     {
           PixelPointInfoCollection.Clear();
           PixelPointInfoCollection.Add(new PointViewModel());
     });
     _cachedPoints.Clear();
 }

运行单元测试时,以下代码卡在Invoke()方法中。

我看到一些关于在调度程序上创建自定义接口并在单元测试中模拟调度程序的文章。 例如http://blog.zuehlke.com/en/mvvm-and-unit-testing/

没有别的办法吗?我有一个庞大的代码库..我现在真的需要改变一切吗?

2016年8月18日更新 现在这就是我所做的,它正在发挥作用

public static class AppServices
{

    public static IDispatcher Dispatcher { get; set; } 
    public static void Init(IDispatcher dispatcher)
    {
        Dispatcher = dispatcher;
    }
}

//this inteface is in order to overrcome MVVM light Dispatcher so we can mock it for unit tests
public interface IDispatcher
{
    void Invoke(Action action);
    void Invoke(Action action, DispatcherPriority priority);
    DispatcherOperation BeginInvoke(Action action);
}

public class DispatcherWrapper :IDispatcher
{
    public DispatcherWrapper()
    {
        DispatcherHelper.Initialize();
    }
    public void Invoke(Action action)
    {
        DispatcherHelper.UIDispatcher.Invoke(action);
    }

    public void Invoke(Action action, DispatcherPriority priority)
    {
        DispatcherHelper.UIDispatcher.Invoke(action, priority);
    }

    public DispatcherOperation BeginInvoke(Action action)
    {
       return DispatcherHelper.UIDispatcher.BeginInvoke(action);
    }
}

所以在app.xaml.cs里面 我打电话 AppServices.Init(new DispatcherWrapper());

在我打电话的单元测试中 AppServices.Init(Substitute.For());

使用NSubstitute

请注意,如果你遗漏了什么东西,我很担心如何让模拟框架运行我以前在

中执行的操作
DispatcherHelper.UIDispatcher.Invoke

1 个答案:

答案 0 :(得分:1)

不幸的是,情况是由于初始设计问题导致代码库难以进行单元测试。为代码创建单元测试的难度与代码设计的好坏直接相关。您在帖子中提到的文章是您需要做的事情,以便访问调度程序,因为它(调度程序)是与UI线程关联的实现问题,在单元测试期间将无法使用。因此锁定Invoke

引用你提到的文章:

  

我们无法测试使用 App.Current.Dispatcher 的代码(因为    App.Current 在单元测试执行期间将为null

     

一种可能的解决方案是创建一个界面 IDispatcher 和一个   实现该接口的 App.Current.Dispatcher 的包装器。

public interface IDispatcher {
    void Invoke(Action action);
    void BeginInvoke(Action action);
}

public class DispatcherWrapper : IDispatcher {
    Dispatcher dispatcher;

    public DispatcherWrapper() {    
        dispatcher = Application.Current.Dispatcher;        
    }
    public void Invoke(Action action) {
        dispatcher.Invoke(action);
    }

    public void BeginInvoke(Action action) {
        dispatcher.BeginInvoke(action);
    }
}