Introduction
I’m currently working on an ASP.NET MVC prototype that 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.
public class HomeController : SecuredBaseController
{
private ISearchAction searchAction;
public HomeController(ISearchAction searchAction)
{
this.searchAction = searchAction;
}
public ActionResult Home()
{
ViewData["Title"] = "Summary";
ViewData["Message"] = "Welcome to ASP.NET MVC!";
SubmissionStatus[] submissionStatusList =
this.searchAction.GetSubmissionStatusForAuditor();
SelectList reviewStatusList = new SelectList(submissionStatusList, "Id",
"InternalDisplayName");
ViewData["ReviewStatusId"] = reviewStatusList;
CountryRegion[] countryList = this.searchAction.GetCountries();
SelectList countrySelectList = new SelectList(countryList, "Id", "Name");
ViewData["CountryId"] = countrySelectList;
Program[] programs = this.searchAction.GetFilteredProgramList();
SelectList programSelectList = new SelectList(programs, "Id", "Name");
ViewData["ProgramId"] = programSelectList;
Item[] activityTypes = this.searchAction.GetActivityTypesForAuditor();
SelectList activityTypesSelectList = new SelectList(activityTypes, "Id", "Name");
ViewData["ActivityTypeId"] = activityTypesSelectList;
return View("ViewPoeSubmissions");
}
You can see that we have a search page that calls a 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>());
.
The Solution
How do we test this? As I mentioned above, the Unity Container is created on Application_Start()
for our website, but since the controller takes an Interface, I can mock that up using the Repository pattern in the Unit Tests.
Here is what the SearchAction
class looks like:
public class SearchAction : IPoeSearchAction
{
private ITaxonomyModel taxonomyModel;
private IRequestModel requestModel;
{
this.taxonomyModel = taxonomyModel;
this.requestModel = requestModel;
}
Notice that the constructor for SearchAction
takes two Interfaces: ItaxonomyModel
and IrequestModel
.
The GetCountries()
method of the SearchAction
class looks like this:
public CountryRegion[] GetCountries()
{
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 the test data.
The RequestModel
class works the same way.
public ClaimSearchResult Search(FormCollection form)
{
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:
private IServiceLocator serviceLocator;
private IUnityContainer unityContainer;
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);
}
[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 that we call the Search
method on the search controller, passing it the form we created, and the code will be applied against our test controllers.
Read more about this at my website.
Chris Aloia lives in the Seattle area and works as a Senior Software Development Engineer for Microsoft Corporation.