For the current post, I'll be showing how you can generate tests for the code developed in the previous post.
We're going to use NUnit and Rhino Mocks for these tests. All the source code and DLLs are included as part of the download, however you'll need to download the NUnit client to run the tests. You could also run the same code using the built-in test framework in Visual Studio 2008; all you have to do is replace the NUnit test attributes with the corresponding Visual Studio test framework.
Download Full Source Code (works with Visual Web Developer Express 2008 Express & Visual Studio 2008)
Note: Modify the XML path(s) to the "DataAccess.cs" file
XElement xArchitects = XElement.Load(@"C:\Architecture\Models\Architects.xml");
Test Project
When you open the solution, you'll see a new project called "ArchitectureTest". In that project there is a Controllers folder where all our controller tests will be located. In addition, there is an "MvcMockHelpers.cs" file that was developed by the ASP.NET MVC team which we'll use to mock HTTP calls.
List Test
First let's test the List action, initialize the Architecture Controller class then use the ViewResult object to store the expected result. From there, you retrieve the Architects collection and then simple check for the desired values or number of collection items.
[Test]
public void List()
{
// Setup
ArchitectureController controller = new ArchitectureController();
// Execute
ViewResult result = controller.List() as ViewResult;
// Verify
IDictionary<string, object> viewData = result.ViewData as IDictionary<string, object>;
var architects = (List<Architect>)viewData["Architects"];
// Test First Element
Assert.AreEqual("Richard Meier", architects[0].FullName);
// Test Number of Elements
Assert.AreEqual(3, architects.Count);
}
Edit Test(s)
If you try to do a similar test for the Edit action, you'll get an error. In the Edit action, there is a check for the HTTP verb "POST" that requires an HTTP context which our current test does not accomplish.
// Incorrect Test
[Test]
public void Edit()
{
// Setup
ArchitectureController controller = new ArchitectureController();
// Execute
ViewResult result = controller.Edit("1", "", "", "") as ViewResult;
// Verify
IDictionary<string, object> viewData = result.ViewData as IDictionary<string, object>;
var architect = (Architect)viewData["Architect"];
// Test First Element
Assert.AreEqual("Richard Meier", architect.FullName);
}
This is where "mocking" comes in play, using Rhino Mocks we create a fake Controller Context, "record" the behavior then "playback" the action.
[Test]
public void Edit()
{
ArchitectureController controller = new ArchitectureController();
MockRepository mocks = new MockRepository();
using (mocks.Record())
{
MvcMockHelpers.SetFakeControllerContext(mocks, controller);
}
using (mocks.Playback())
{
ViewResult result = controller.Edit("101", "", "", "") as ViewResult;
IDictionary<string, object> viewData = result.ViewData as IDictionary<string, object>;
var architect = (Architect)viewData["Architect"];
Assert.AreEqual("Richard Meier", architect.FullName);
}
}
Next we need to modify the HTTP verb to test if any errors are returned or any of the code that happens after the check for "POST" in the controller class. Setting the HTTP verb to "POST" allows us to fully test the remaining code in the Edit action in "ArchitectureController.cs"; by passing empty parameters in our Edit action call, validation errors are populated in the "errors" collection and we can run tests against it.
[Test]
public void EditPost()
{
// Setup
ArchitectureController controller = new ArchitectureController();
MockRepository mocks = new MockRepository();
using (mocks.Record())
{
MvcMockHelpers.SetFakeControllerContext(mocks, controller);
var context = controller.ControllerContext.HttpContext;
context.Request.SetHttpMethodResult("POST");
mocks.ReplayAll();
}
using (mocks.Playback())
{
// Test Errors
ViewResult result = controller.Edit("101", "", "", "") as ViewResult;
IDictionary<string, object> viewData = result.ViewData as IDictionary<string, object>;
var errors = (List<string>)viewData["errors"];
Assert.AreEqual(3, errors.Count);
// Test Errors
result = controller.Edit("101", "Richard Meier", "Getty Center", "") as ViewResult;
viewData = result.ViewData as IDictionary<string, object>;
errors = (List<string>)viewData["errors"];
Assert.AreEqual(1, errors.Count);
}
}
For more information on testing/mocking by the ASP.NET MVC Team:
- Screencast that explains the basic steps; even though it was done for Preview 2 it still applies to Preview 4.
- Article for additional testing scenarios such as testing for redirection


0 comments:
Post a Comment