2012-02-17 38 views
5

私は、nUnitテストを実行するために、Using the WPF Dispatcher in unit testsの提案に従おうとしています。単体テストで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; 
    } 
} 

I DispatcherUtilを使用している場合、ExitFrameの呼び出しがデータが準備が整う前に早すぎるように見えます。

DispatcherUtilを正しく使用していませんか?これは、ビューモデルからのコールバックを待つのではなく、ディスパッチャーを処理するためのより良い方法のようです。

+0

あなたはPropertyChangedEventHandlerは、「データ」の特性のために呼び出されただけの場合は、テストしようとしていますか?もしそうなら、なぜあなたはディスパッチャーを関与させる必要がありますか?また、ハンドラをアタッチするために_myViewModelを使用しないでください。 – Phil

+0

@Phil:_myViewModelがインスタンス化されると、コンストラクタはasyn呼び出しを行います。その呼び出しが完了すると、_myViewModel.Dataはいくつかの値を持つ必要があります。実際にDataが実装されていることをテストしようとしていますが、asyn呼び出しの結果Dataにデータが入力されているという事実が私に何らかの問題を引き起こしています。 Dispatcherを処理する必要のある単体テストでPropertyChangedイベントを聴かなくてもいいです。 – Flack

答えて

7

ユニットテストでディスパッチャが問題になるため、私の解決策は、ディスパッチャに対するビューモデルの依存関係を解除することです。 - 私たちは、ディスパッチャ作品を引き受けることができ

Dispatcher.CurrentDispatcher.BeginInvoke(.. 

ディスパッチャは、外部依存関係であり、あなたのユニットテストの一部であってはならない。私は現在、あなたがハードのような参照をコード化していることを前提としています。

私は依存性注入(貧乏人、Unityなど)を使用します。 ディスパッチャを表す適切なインタフェースを作成します。 実際のディスパッチャをラップする実際の実装を作成します。 Action.BeginInvokeを使用する偽の実装を作成します。 偽では、すべてのIAsyncResultsをBeginInvokeの呼び出しに返して記録します。
それから、すべての呼び出しが完了するのを待つヘルパーメソッドがあります。これは、テストで完了を待つために使用できます。

同じことをするビューモデルの基本クラスがあります。通常はディスパッチャを呼び出しますが、テスト中に偽の電話をかけるよう指示することができます。

0

私は簡単な解決策を見つけました。 DispatcherでFrames Asyncを処理する代わりに、別の同期メソッドを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; 
     } 
    } 
関連する問題