Wednesday, February 4, 2009

Using a Unity Container with Service Locator for Test Driven Development

Read more about this article at my web site.

If you read my page on Unity Container and Service Locator, the page on Using Unity and Service Locator for Unit Testing brings them together.



So how do I use a unity container for Test Driven Development?



This is the really cool part of DI containers, since you’re using Dependency Injection via Interfaces, you can change behavior at runtime.



Since I’m currently working on an ASP.Net MVC prototype I’m going to demonstrate Unity Testing a Controller which uses Dependency Injection.



In my case I’m using ASP.Net MVC controllers that have a dependency on certain actions. I wanted to keep the controller as clean as possible so I created an Iaction interface.



Let’s call it HomeController for now.





/// <summary>



/// HomeController class.



/// </summary>



public class HomeController : SecuredBaseController



{



/// <summary>



/// Search Action Interface.



/// </summary>



private ISearchAction searchAction;





/// <summary>



/// Constructor for Home Controller.



/// </summary>



/// <param name="searchAction">Home page search action.</param>



public HomeController(ISearchAction searchAction)



{



this.searchAction = searchAction;



}





/// <summary>



/// Load view Index.



/// </summary>



/// <returns>Action Result.</returns>



public ActionResult Home()



{



ViewData["Title"] = "Summary";



ViewData["Message"] = "Welcome to ASP.NET MVC!";





//// get valid review status



SubmissionStatus[] submissionStatusList = this.searchAction.GetSubmissionStatusForAuditor();





SelectList reviewStatusList = new SelectList(submissionStatusList, "Id", "InternalDisplayName");



ViewData["ReviewStatusId"] = reviewStatusList;





//// primary countries



CountryRegion[] countryList = this.searchAction.GetCountries();



SelectList countrySelectList = new SelectList(countryList, "Id", "Name");



ViewData["CountryId"] = countrySelectList;





//// get programs



Program[] programs = this.searchAction.GetFilteredProgramList();



SelectList programSelectList = new SelectList(programs, "Id", "Name");





ViewData["ProgramId"] = programSelectList;





//// get activity types



Item[] activityTypes = this.searchAction.GetActivityTypesForAuditor();





SelectList activityTypesSelectList = new SelectList(activityTypes, "Id", "Name");





ViewData["ActivityTypeId"] = activityTypesSelectList;





return View("ViewPoeSubmissions");



}





Ok so you can see that we have a search page that calls an Search Action interface with all the code contained in a SearchAction class. The SearchAction class is in a, you guessed it.. Unity Container. I won’t go into the factory class that creates the unity container right now, I’ll write another article on that item but for now, the Unity container is actually created on Application_Start() and looks something like: ControllerBuilder.Current.SetControllerFactory(UnityContainers.Instance.Resolve<IControllerFactory>());



So how do we test this? As I mentioned above, the untiy container is created on Application_Start() for our web site but since the controller takes an Interface, I can mock that up using a Repository pattern in the Unit Tests.



Here is what the SearchAction class looks like:



/// <summary>



/// Search action class for the controller.



/// </summary>



public class SearchAction : IPoeSearchAction



{



/// <summary>



/// Taxonomy model interface.



/// </summary>



private ITaxonomyModel taxonomyModel;





/// <summary>



/// Activity request model interface.



/// </summary>



private IRequestModel requestModel;





/// <summary>



/// Search Action.



/// </summary>



/// <param name="taxonomyModel">Taxonomy Model Interface.</param>



/// <param name="requestModel">Request Model Interface.</param>public SearchAction(ITaxonomyModel taxonomyModel, IRequestModel requestModel)



{



this.taxonomyModel = taxonomyModel;



this.requestModel = requestModel;



}







Notice the constructor for Search Action takes 2 interfaces, ItaxonomyModel and IrequestModel.



The GetCountries() method of the SearchAction class looks like this:



/// <summary>



/// Get list of primary countries.



/// </summary>



/// <returns>Country region collection.</returns>



public CountryRegion[] GetCountries()



{



// Grab the Instance from Activity Request Process.



return this.taxonomyModel.GetCountries();



}





It’s actually the TaxonomyModel class that calls the web service and takes care of the GetCountries() code so I can create a class called TestTaxonomyModel that implements the ItaxonomyModel interface and in that test class I can put mock code in the GetCountries method that will return a subset of Test Data.













The RequestModel class works the same way.



/// <summary>



/// Search for a Claim.



/// </summary>



/// <param name="form">Form Collection.</param>



/// <returns>Activity Based Claim Search Result.</returns>



public ClaimSearchResult Search(FormCollection form)



{





/// Create some search criteria from the form data.



ClaimSearchCriteria criteria = this.CreateSearchCriteria(form);





return this.requestModel.SearchClaims(searchCriteria);





}



I can create a class called TestRequestModel that implements the IRequestModel interface and put logic to return test data based upon the search criterion passed in.



Here is what my unit test looks like. First I initialize a unity container with test data:



/// <summary>



/// Internal chip service locator.



/// </summary>



private IServiceLocator serviceLocator;





/// <summary>



/// Unity container.



/// </summary>



private IUnityContainer unityContainer;





/// Initialize tests.



/// </summary>



TestInitialize]



public void InitializeTests()



{





this.unityContainer = new UnityContainer()



.RegisterType<IController, HomeController>()



.RegisterType<ISearchAction, SearchAction>();





this.unityContainer.Configure<InjectedMembers>()



.ConfigureInjectionFor<SearchAction>(new InjectionConstructor(new object[] { new TestTaxonomyModel(), new TestRequestModel() }))





.ConfigureInjectionFor<HomeController>(new InjectionConstructor(this.unityContainer.Resolve<ISearchAction>()));





unityContainer.Resolve<IController>();





this.serviceLocator = new MyServiceLocator(this.unityContainer);





}



/// <summary>



/// Search test method.



/// </summary>



[TestMethod]



public void SearchTest()



{



var homeController = new HomeController(this.serviceLocator.GetInstance<SearchAction>());





FormCollection form = new FormCollection();





form["ProgramId"] = "3";



form["ActivityId"] = "8";



form["CountryId"] = "33";



form["Filter"] = "3";



form["Region"] = "Foo";





searchController.Search(form);





}



There – you can see it is above, we call the Search method on the search controller psssing it the form we created and the code will be applied against our test controllers.





Regards,



-c

No comments:

Post a Comment