2009-07-24 3 views
2

Я создаю базовую составную WPF-оболочку с одним модулем. Я бы хотел, чтобы модуль тестировал мой модуль. По-видимому, Composite WPF модулирует мой код таким образом, что он должен быть простым для тестирования.В Composite WPF (Prism), как я должен тестировать свои контроллеры?

Ниже приведен код, который я хотел бы проверить. Он находится в контроллере моего модуля. Обратите внимание на использование стандартных сущностей Composite WPF, как регионы, Ведущие, модели и т.д.

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); 
    } 

Это только семь строк кода, я хочу модульного тестирования. Не плохо. Проблема в том, что это зависит от ряда внешних компонентов: RegionManager, View, PresentationModel и т. Д.

Чтобы проверить это самостоятельно, выполните следующие действия. Они передаются в мой контроллер через инсталляцию конструктора с использованием контейнера Unity. Чтобы настроить это и выполнить простой тест, мой модульный тест выглядит следующим образом:

(Посмотрите на длину этого метода! Конечно, должен быть лучший способ проверить? Составляет ли составной WPF мою жизнь? проще? И я должен сделать это для каждого теста ?!)

[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

Я столкнулся с этим сам с классами с большим количеством зависимостей. Там действительно не так много.

Действительно ли ваш метод зависит от всех этих классов? Я вижу только две или три зависимости, которые используются здесь (IRegionManager, IPlantTreePresentationModel). Те должны быть единственными, у вас есть, чтобы издеваться над вашим методом. Вы можете проверить это, используя набор зависимостей, подходящий для вашего теста, а не для любого теста этого объекта.

Другое, что вы могли бы подумать, - сколько из этих зависимостей вы можете включить в код запуска вашего теста (метод, украшенный [TestInitialize]). Некоторые общие зависимости и ваш контейнер могут жить в рамках всего тестового набора, особенно если они не меняются за каждый тест.

Зависимость от инъекции, конечно, делает вашу жизнь проще, даже если вы ее не понимаете. Я считаю, что многие люди, которые делают «модульное тестирование», на самом деле не делают это правильно и делают функциональное тестирование из-за того, что у них нет надлежащей изоляции от других частей своего приложения.

Инъекционная инъекция почти заставляет вас задуматься о модели, где вы можете полностью изолировать код, который вы хотите проверить, от всех других частей вашего приложения. Это может стоить немного впереди, но качество ваших модульных тестов и гранулярность обратной связи, которую вы получаете от них, перевесят эти затраты, особенно когда вы займетесь в своем жизненном цикле и начнете рефакторинг. Тогда ты будешь благодарен. Придерживаться.

+0

Отличный совет, спасибо Андерсон. Я посмотрю, как я могу это упростить. Перемещение некоторых зависимостей в метод установки имеет смысл. Интересно, могу ли я, возможно, использовать некоторые из конкретных классов Призмы? (то есть, если я действительно издеваюсь над IEventAggregator?) – willem

Смежные вопросы