Code Analysis doesn’t like the former MVC pattern of using a catch for all errors when updating a model. I wanted to use the HandleError attribute to deal with errors, but how should I unit test it?
There are several keys to having the HandleError attribute work:
- Must decorate the Action with [HandleError]
- Must have <customErrors Mode=”On” /> in the web.config
- Must have an Errors view in the Views/Shared directory
I’m more concerned with the first two and unit testing those is what I cover here.
Action has HandleError attribute
Here’s is what the Edit action looks like on my AdminController:
- [HandleError]
- [HttpPost, Authorize(Roles = RoleNames.Admin)]
- public ViewResult Edit(string id, FormCollection collection)
- {
An here is the unit test that will verify I have the HandleError attribute on, and further, that it will point to the Errors view (the default).
- [TestCategory("Build"), TestMethod]
- public void Edit_User_InvalidData()
- {
- // Arrange
- var expected = "Error";
- // Get the Edit method that is used for the post –
- // The one that takes the userName (email) and the FormCollection.
- MethodInfo method = typeof(AdminController).GetMethod("Edit",
- new Type[] { typeof(string), typeof(FormCollection) });
- // Act
- var attributes = method.GetCustomAttributes(typeof(HandleErrorAttribute), true);
- // Assert
- var errorAttribute = (HandleErrorAttribute)attributes[0];
- var actual = errorAttribute.View;
- Assert.AreEqual(expected, actual);
- }
CustomErrors Mode is On
The next challenge was to make sure that the customError Mode is set to On. It doesn’t matter if you have the HandleError attribute if the customError Mode is Off. This test was a bit more challenging.
As I unit test the MVC application, it will copy the web.config file into my TestDeployment directory. To get to that I need to have the TestContext. Here is that code:
- private TestContext _testContextInstance;
- /// <summary>
- /// Gets or sets the test context which provides
- /// information about and functionality for the current test run.
- ///</summary>
- public TestContext TestContext
- {
- get { return _testContextInstance; }
- set { _testContextInstance = value; }
- }
Next, I need to map the web.config file. That seemed to be very tricky:
- private WebConfigurationFileMap CreateTestFileMap()
- {
- var fileMap = new WebConfigurationFileMap();
- var virtualDirectoryMapBase = new VirtualDirectoryMapping(TestContext.TestDeploymentDir, true, "web.config");
- fileMap.VirtualDirectories.Add("/", virtualDirectoryMapBase);
- return fileMap;
- }
Finally, the actual unit test to validate that my web.config file is correct. This test will fail if I change my web.config file to have <customErrors mode=”Off” />, but passes if it’s on.
- [TestCategory("Build"), TestMethod]
- public void CustomErrors_Are_On()
- {
- // Arrange
- var expected = CustomErrorsMode.On;
- var mappedFile = CreateTestFileMap();
- var config = WebConfigurationManager.OpenMappedWebConfiguration(mappedFile, "/");
- var sectionGroup = config.GetSection("system.web/customErrors") as CustomErrorsSection;
- // Act
- var actual = sectionGroup.Mode;
- // Assert
- Assert.AreEqual(expected, actual);
- }
Not terribly easy, but this will make sure that I have the right setup before I deploy my site. I hope this saves someone else all the trouble this took me…
Leave a Reply