2012-02-17 40 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; 
     } 
    } 
相關問題