I am attempting to test the Index
action of a controller. The action uses AutoMapper to map a domain Customer
object to a view model TestCustomerForm
. While this works I am concerned about the best way to test the results that I am receiving from the Index
action.
The controller's index action looks like this:
public ActionResult Index()
{
TestCustomerForm cust = Mapper.Map<Customer,
TestCustomerForm>(_repository.GetCustomerByLogin(CurrentUserLoginName));
return View(cust);
}
And its TestMethod
looks like this:
[TestMethod]
public void IndexShouldReturnCustomerWithMachines()
{
// arrange
var customer = SetupCustomerForRepository(); // gets a boiler plate customer
var testController = CreateTestController();
// act
ViewResult result = testController.Index() as ViewResult;
// assert
Assert.AreEqual(customer.MachineList.Count(),
(result.ViewData.Model as TestCustomerForm).MachineList.Count());
}
In the CreateTestController
method I use Rhino.Mocks
to mock a customer repository and set it up to return the customer from SetupCustomerForRepository
. In this manner I know that the repository will return the intended customer when the Index
action calls _repository.GetCustomerByLogin(CurrentUserLoginName)
. Therefore, I figure asserting an equal count is adequate to satisfy IndexShouldReturnCustomerWithMachines
.
All of that said I am concerned as to what I should be testing.
- It seems presumptuous to cast the
result.ViewData.Model as TestCustomerForm
. Is this really an issue? This concerns me because in this instance I am not truly doing test driven development and it seems like I am counting on a particular implementation to satisfy the test. - Are there more appropriate tests to ensure correct mapping?
- Should I be testing each mapped property from the
TestCustomerForm
? - Are there more general controller action tests that I should be doing?
This is one of the reasons why we move AutoMapper into a custom ActionResult or an ActionFilter. At some point, you only really want to test that you mapped Foo to FooDto, but not necessarily test the actual mapping. By moving AutoMapper into the layer boundaries (such as between controller an view), you can merely test what you're telling AutoMapper to do.
This is similar to testing a ViewResult. You don't test from a controller that a view was rendered, but rather that you told MVC to render such-and-such view. Our action result becomes:
With a helper method on a base controller class:
Which then makes the controller now only specify what to map to/from, instead of performing the actual mapping:
At this point, I only need to test, "make sure that you're mapping this Foo object to this destination FooDto type", without needing to actually perform the mapping.
EDIT:
Here's an example of a test snippet:
I would probably separate the coupling between
AutoMapper
and the controller by introducing an abstraction:Next you pass this into the controller:
And in your unit test you would use your favorite mocking framework to stub this mapper.