2009-07-24 3 views
2

私は1つのモジュールで基本的なコンポジットWPFシェルを構築しています。モジュールの単体テストをしたいです。明らかに、コンポジットWPFは単体テストを容易にするような方法でコードをモジュール化しています。Composite WPF(Prism)では、コントローラーの単体テストはどのように行うべきですか?

以下は単体テストにしたいコードです。それは私のモジュールのコントローラにあります。地域、プレゼンター、モデルなど

public void ShowPlantTreeView() 
    { 
     IRegion navRegion = this.regionManager.Regions[RegionNames.NavigationRegion]; 
     IPlantTreeView view = navRegion.GetView(typeof(IPlantTreeView).Name) as IPlantTreeView; 
     if (view == null) 
     { 
      view = this.container.Resolve<IPlantTreePresentationModel>().View; 
      navRegion.Add(view, typeof(IPlantTreeView).Name); 
     } 

     view.Model.LastRefreshDateTime = DateTime.Now; 
     navRegion.Activate(view); 
    } 

これは、ユニットテストに私が欲しいのコードの唯一の7行であるような標準的なコンポジットWPF実体の使用に注意してください。悪くない。問題は、それがいくつかの外部コンポーネント(RegionManager、View、PresentationModelなど)に依存することです。

これを個別にテストするために、外部コンポーネントをモックします。これらはUnityコンテナを使用してコンストラクタインジェクションを通して私のコントローラに渡されます。これを設定して簡単なテストをするために、私の単体テストは次のようになります。

(このメソッドの長さを見てください!確かにテストする方が良いでしょうか?私はすべてのテストでこれを行う必要がありますか?)

[TestMethod] 
    public void TestShowPlantTree() 
    { 
     //Setup Mocks. 
     var plantTreePresentationModel = new Mock<IPlantTreePresentationModel>(); 
     var plantTreeViewMock = new Mock<IPlantTreeView>(); 
     var navRegionMock = new Mock<IRegion>(); 
     var plantTreeModuleMock = new Mock<IPlantTreeModule>(); 
     var regionManagerMock = new Mock<IRegionManager>(); 
     var eventAggregatorMock = new Mock<IEventAggregator>(); 
     var shellControllerMock = new Mock<IShellController>(); 
     var plantTreeNodeSelectedEventMock = new Mock<PlantTreeNodeSelectedEvent>(); 

     plantTreeViewMock.Setup(v => v.Model).Returns(plantTreePresentationModel.Object); 
     container.RegisterInstance<IPlantTreePresentationModel>(plantTreePresentationModel.Object); 
     regionManagerMock.Setup(o => o.Regions[RegionNames.NavigationRegion]).Returns(navRegionMock.Object); 
     navRegionMock.Setup(r => r.GetView(typeof(IPlantTreeView).Name)).Returns(plantTreeViewMock.Object); 
     navRegionMock.Setup(r => r.Activate(plantTreeViewMock.Object)); 
     plantTreePresentationModel.SetupSet(m => m.LastRefreshDateTime); 
     eventAggregatorMock.Setup(a => a.GetEvent<PlantTreeNodeSelectedEvent>()).Returns(plantTreeNodeSelectedEventMock.Object); 


     //Setup container. 
     container.RegisterType<IPlantTreeController, PlantTreeController>(); 
     container.RegisterInstance<IPlantTreePresentationModel>(plantTreePresentationModel.Object); 
     container.RegisterInstance<IPlantTreeView>(plantTreeViewMock.Object); 
     container.RegisterInstance<IRegion>(navRegionMock.Object); 
     container.RegisterInstance<IPlantTreeModule>(plantTreeModuleMock.Object); 
     container.RegisterInstance<IRegionManager>(regionManagerMock.Object); 
     container.RegisterInstance<IEventAggregator>(eventAggregatorMock.Object); 
     container.RegisterInstance<IShellController>(shellControllerMock.Object); 
     container.RegisterInstance<PlantTreeNodeSelectedEvent>(plantTreeNodeSelectedEventMock.Object); 


     //Initialize controller to be tested. 
     IPlantTreeController controllerToTest = container.Resolve<IPlantTreeController>(); 

     controllerToTest.ShowPlantTreeView(); 


     //Test if controller interacted with the mocks as expected. 
     plantTreePresentationModel.VerifyAll(); 
     regionManagerMock.VerifyAll(); 
     navRegionMock.VerifyAll(); 
    } 

私のクラスをテストする良い方法はありますか?アドバイスをいただければ幸いです。

答えて

1

私は多くの依存関係を持つクラスでこれを自分で実行しました。周囲にはあまり道はありません。

あなたのメソッドは本当にこれらのクラスすべてに依存していますか?ここでは、2つまたは3つの依存関係(IRegionManager、IPlantTreePresentationModel)のみが利用されています。それらは唯一のものであるべきですあなたの方法をテストするために模擬する。このオブジェクトのテストではなく、テストに適した一連の依存関係を使用してテストできます。

他にも、テストのスタートアップコード([TestInitialize]で装飾されたメソッド)を考慮に入れることができる依存関係の数がいくつかあります。一般的な依存関係やコンテナは、テストごとに変更されない場合は、テストスイート全体のスコープ内に存在する可能性があります。

依存性注入は、気づいていなくても、あなたの人生を楽にします。私は、「ユニットテスト」を行っている多くの人が本当に正しいことをしておらず、アプリの他の部分から適切なアイソレーションを持っていないため、機能テストを行っていることがわかりました。

依存性注入は、実際にアプリケーションの他の部分すべてからテストするコードを完全に分離できるモデルになります。ちょっと手間がかかるかもしれませんが、単体テストの品質とフィードバックの細かさは、特にアプリケーションのライフサイクルの後半になってリファクタリングを開始するときにかかるコストを上回ります。あなたはあなた自身に感謝するでしょう。それにこだわります。

+0

大きなアドバイス、感謝アンダーソン。私はそれをどのように単純化できるかを見ていきます。いくつかの依存関係をsetupメソッドに移すことは理にかなっています。私はおそらく、具体的なプリズムのクラスのいくつかを使用すべきかどうか疑問に思いますか? (つまり、IEventAggregatorを実際に模擬すべきですか?) – willem

関連する問題