2011-01-06 3 views
2

ここにはスレッドジャンクティのためのものがあります。私はこのメソッドを持っています:WPockとディスパッチャに対するNMockの問題のテスト

public void RefreshMelts() 
    { 
     MeltsAvailable.Clear(); 

     ThreadPool.QueueUserWorkItem(delegate 
     { 
      Dispatcher.BeginInvoke((ThreadStart)delegate 
      { 
       eventAggregator.GetEvent<BusyEvent>().Publish(true); 
       eventAggregator.GetEvent<StatusMessageEvent>().Publish(
        new StatusMessage("Loading melts...", MessageSeverity.Low)); 
      }); 

      try 
      { 
       IList<MeltDto> meltDtos = meltingAppService.GetActiveMelts(); 

       Dispatcher.Invoke((ThreadStart)delegate 
       { 
        foreach (MeltDto availableMelt in meltDtos) 
        { 
         MeltsAvailable.Add(availableMelt); 
        } 
        OnPropertyChanged("MeltsAvailable"); 

        eventAggregator.GetEvent<BusyEvent>().Publish(false); 
        eventAggregator.GetEvent<StatusMessageEvent>().Publish(
         new StatusMessage("Melts loaded", MessageSeverity.Low)); 
       }); 
      } 
      catch (ApplicationException ex) 
      { 
       log.Error("An error occurred in MeltsViewModel when attempting to load melts", ex); 

       Dispatcher.Invoke((ThreadStart)delegate 
       { 
        MeltsAvailable.Clear(); 

        eventAggregator.GetEvent<StatusMessageEvent>().Publish(
         new StatusMessage("Melt data could not be loaded because an error occurred; " + 
          "see the application log for detail", 
          MessageSeverity.High)); 
        eventAggregator.GetEvent<BusyEvent>().Publish(false); 
       }); 
      } 

     }); 

    } 

これは、WPFユーザーコントロールで定義されています。 MeltsAvailableはMeltDtosのObservableCollectionです。このコードは、アプリケーション自体で実行するときれいに動作します。

問題は、このメソッドの結果を確認するために、NMockを使用して単体テストを作成することです。具体的には、一度呼び出されるとMeltsAvailableプロパティにいくつかの項目があります。テスト方法は次のとおりです。

[TestMethod] 
    public void GetAvailableMeltsTest() 
    { 
     MeltDto mockMelt1 = new MeltDto(); 
     MeltDto mockMelt2 = new MeltDto(); 

     mockMelt1.MeltIdentifier = "TST0001"; 
     mockMelt2.MeltIdentifier = "TST0002"; 

     IList<MeltDto> availableMelts = new List<MeltDto>(); 
     availableMelts.Add(mockMelt1); 
     availableMelts.Add(mockMelt2); 

     Expect.Exactly(1).On(service).Method("GetActiveMelts").Will(Return.Value(availableMelts)); 


     MeltsViewModel vm = new MeltsViewModel(aggregator, logger, service, configManagerFactory); // All of these are mock objects 

     vm.RefreshMelts(); 
     Thread.Sleep(millisecondDelayForEventPublish * 100); 

     mockery.VerifyAllExpectationsHaveBeenMet(); 

     Assert.AreEqual(vm.MeltsAvailable.Count, 2); 
     Assert.AreEqual(vm.MeltsAvailable[0].MeltIdentifier, "TST0001"); 
     Assert.AreEqual(vm.MeltsAvailable[1].MeltIdentifier, "TST0002"); 

    } 

最初のAssert.AreEqualでテストが一貫して失敗します。 vm.MeltsAvailableはその時点では空です。

私は、すべてのスレッドを取り除くと同じようにそれを残す場合は、次のテストパス

public void RefreshMelts() 
    { 
     MeltsAvailable.Clear(); 
     IList<MeltDto> meltDtos = meltingAppService.GetActiveMelts(); 
     foreach (MeltDto availableMelt in meltDtos) 
     { 
      MeltsAvailable.Add(availableMelt); 
     } 
     OnPropertyChanged("MeltsAvailable"); 
    } 

明らかに、スレッドに関して嫌いなことがありますが、Debug-> Exceptions-> CLR Exceptions-> Thrownをオンにして、Just My Codeをオフにしても、RefreshMelts 。

私がMeltDtoオブジェクトをMeltsAvailableコレクションにロードするDispatcher.Invoke呼び出しが、決して呼び出されないように見えることは、もっとも不思議な部分です。セクション全体をブレークポイントで覆うことができ、決してヒットしません。スレッドを押し上げる。私のテストでは10秒という最高の時間で何も変わりません。

なぜですか?なぜ、そのセクションが実行されていないのですか、なぜ私はそれに侵入したり、侵入したりすることができません、どうして例外が発生しないのですか?

おかげでずっと、 スティーブ

答えて

4

ディスパッチャは、実行中のスレッドに結び付けられているメッセージループです。メインスレッドがアイドル状態のときにキュー内の項目を処理します。単体テストでは決して起こらない。スレッドがビジーで、テストが完了するとスレッドが終了します。

Visual Studioを使用してテストを実行している場合、コードカバレッジの強調表示をオンにすると、Dispatcher.Invoke()内のコードが呼び出されない(赤で表示される)ことがわかります。

DispatcherFrameを使用して、キューに入れられたメッセージを処理するDispatcherをトリガーすることができます。コールDispatcherHelper.DoEvents(前アサーションに)あなたのテストの終わりに

public static class DispatcherHelper 
{ 
    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; 
    } 
} 

():あなたのユニットテストプロジェクトに、次のヘルパークラスを追加します。これにより、ディスパッチャが未処理のイベント(ビューモデルの監視可能なコレクションに項目を追加するイベントなど)を処理します。その後、ビューモデルのプロパティを調べて、それらが正しく設定されていることを確認できます。

関連する問題