2012-02-17 49 views
5

我试图按照Using the WPF Dispatcher in unit tests的建议来使我的nUnit测试运行。在单元测试中使用WPF调度程序的正确方法

当我写我的单元测试如下,它的工作原理:

[Test] 
public void Data_Should_Contain_Items() 
{ 
    DispatcherFrame frame = new DispatcherFrame(); 
     PropertyChangedEventHandler waitForModelHandler = delegate(object sender, PropertyChangedEventArgs e) 
     { 
      if (e.PropertyName == "Data") 
      { 
      frame.Continue = false; 
      } 
     }; 
    _myViewModel.PropertyChanged += waitForModelHandler; 
    Dispatcher.PushFrame(frame); 

    Assert.IsTrue(_myViewModel.Data.Count > 0, "Data item counts do not match"); 
} 

但是,如果我尝试使用DispatcherUtil的建议,这是行不通的:

[Test] 
public void Data_Should_Contain_Items() 
{ 
    DispatcherUtil.DoEvents(); 
    Assert.IsTrue(_myViewModel.Data.Count > 0, "Data item counts do not match"); 
} 

public static class DispatcherUtil 
{ 
    [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] 
    public static void DoEvents() 
    { 
     DispatcherFrame frame = new DispatcherFrame(); 
     Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, 
      new DispatcherOperationCallback(ExitFrame), frame); 
     Dispatcher.PushFrame(frame); 
    } 

    private static object ExitFrame(object frame) 
    { 
     ((DispatcherFrame)frame).Continue = false; 
     return null; 
    } 
} 

当我我正在使用DispatcherUtil,在数据准备就绪之前,看起来对ExitFrame的调用发生得太快。

我没有正确使用DispatcherUtil?这似乎是一个更好的方法来处理调度程序,而不是等待视图模型的回调。

+0

什么是你想测试,只是如果PropertyChangedEventHandler被调用属性“数据”?如果是这样,你为什么需要调度员?我也不使用_myViewModel来附加处理程序。 – Phil 2012-02-18 08:46:44

+0

@Phil:当_myViewModel被实例化时,它的构造函数进行asyn调用。当该调用完成时,_myViewModel.Data应该有一些值。我试图测试数据实际上是否已被填充,但数据是由asyn调用填充的事实是什么导致我遇到了一些麻烦。我想避免在任何可能不得不处理Dispatcher的单元测试中收听PropertyChanged事件。 – Flack 2012-02-18 23:49:15

回答

7

由于调度器在单元测试中有问题,我的解决方案是打破你的视图模型对调度器的依赖。我认为像目前你已经硬编码引用:

Dispatcher.CurrentDispatcher.BeginInvoke(.. 

调度员是一个外部的依赖,不应该是你的单元测试的一部分 - 我们可以假设调度工作。

我会使用依赖注入(穷人,统一等)。 创建一个合适的界面代表调度员。 创建包装真正调度程序的真正实现。 创建一个使用Action.BeginInvoke的假实现。 在假冒中,您记录了所有返回到调用BeginInvoke的IAsyncResults。
然后有一个辅助方法,它会等待所有可以完成的调用,您可以在测试中使用它来等待完成。

或者有一个视图模型基类可以做同样的事情。通常调用调度员,但可以在测试过程中指示调用假。

0

我找到了一个简单的解决方案。我没有在分派器中处理帧异步,​​而是向DispatcherUtil类添加了另一个同步方法。调用此DoEventsSync() - 返回时,所有的帧进行了处理,我认为这应该有助于在这里:​​

public static class DispatcherUtil 
    { 
     [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] 
     public static void DoEvents() 
     { 
      var frame = new DispatcherFrame(); 
      Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, 
       new DispatcherOperationCallback(ExitFrame), frame); 
      Dispatcher.PushFrame(frame); 
     } 

     public static void DoEventsSync() 
     { 
      var frame = new DispatcherFrame(); 
      Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, 
       new DispatcherOperationCallback(ExitFrame), frame); 
      Dispatcher.PushFrame(frame); 
     } 

     private static object ExitFrame(object frame) 
     { 
      ((DispatcherFrame)frame).Continue = false; 
      return null; 
     } 
    } 
相关问题