***** DISCLAIMER *****
The techniques and information here were not all thought up by me. I got a lot of this from Scott Hanselman's screencasts, and at looking at other MVC projects. I am only putting this into a post to have a single point of reference for the next guy.
***** END DISCLAIMER *****
One of the main goals of the new ASP.Net MVC framework is to allow for easier testing of web applications. One of the things that is now easily testable is controller actions.
Before we get started, there are a few things you are going to need in order to test controller actions.
- RhinoMocks (or any other mocking framework)
- The MVCMockHelper from Phil Haack
- A fake view Engine to use
public class FakeViewEngine : IViewEngine
{
public ViewContext ViewContext { get; private set; }
public void RenderView(ViewContext viewContext)
{
ViewContext = viewContext;
}
}
Ok, on to the actual test code.
[Test]
public void SportsEdit_Verify_Correct_Actions()
{
// Point 1
MockRepository mocker = new MockRepository();
ISportService sportServiceMock = mocker.CreateMock();
SportsController myController = new SportsController();
FakeViewEngine fakeViewEngine = new FakeViewEngine();
myController.ViewEngine = fakeViewEngine;
// Point 2
// Create my mock sport to be returned
Sports sportsMock = mocker.CreateMock(new Sport {SportID = 1, Description = "Desc", Name = "Name"});
// Point 3
// Tell StuctureMap we want a mock, not the real thing
ObjectFactory.InjectStub(typeof(ISportService), sportServiceMock);
// Point 4
// setup the expectation on my call into my service
Expect.Call(sportServiceMock.GetSports(1)).IgnoreArguments().Return( sportsMock );
// Point 5
// Setup all expectations for the mocking engine
mocker.SetFakeControllerContext(myController);
mocker.ReplayAll();
// Point 6
// call the actual controller method.
myController.SportsDetails( 1 );
// Point 7
Assert.That( "SportsEdit", Is.EqualTo( fakeViewEngine.ViewContext.ViewName ) );
Assert.That(sportsMock, Is.EqualTo(fakeViewEngine.ViewContext.ViewData));
}
I will break the code above into multiple sections to better explain what is going on.
- Here we are setting up the mock engine and creating any objects that are going to be needed during the test later.
- Need to create the object to return later during our expected call via our service
- Need to tell StructureMap what to do when someone asks for a ISportService. In this case we want to mock it out since we DO NOT want to do a round trip.
- Setup the correct expectation on the mock service (needed to avoid the round trip)
- This is the important step, this is where we are making use of the MVCMocking helper stuff. In here we are going to setup all sorts of mocks for later use.
NOTE - If you forget this step you will get a NullReference exception when calling your controller
- Make the call into the actual controller. This is testing the call as if it were being called by the IIS during the controller call.
- We are asserting that the correct view name is being called and we have passed along the correct view data as well.
I am pretty sure there are other ways to test controller actions. In fact I have seen them. But so far this is my favorite way.
Let me know what you think.
Till next time,