Unit Testing HandleErrorAttribute

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:

Edit Action on AdminController
  1. [HandleError]
  2. [HttpPost, Authorize(Roles = RoleNames.Admin)]
  3. public ViewResult Edit(string id, FormCollection collection)
  4. {

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).

Test HandleErrorAttribute
  1. [TestCategory("Build"), TestMethod]
  2. public void Edit_User_InvalidData()
  3. {
  4.     // Arrange
  5.     var expected = "Error";
  6.     // Get the Edit method that is used for the post –
  7.     // The one that takes the userName (email) and the FormCollection.
  8.     MethodInfo method = typeof(AdminController).GetMethod("Edit",
  9.         new Type[] { typeof(string), typeof(FormCollection) });
  10.  
  11.     // Act
  12.     var attributes = method.GetCustomAttributes(typeof(HandleErrorAttribute), true);
  13.  
  14.     // Assert
  15.     var errorAttribute = (HandleErrorAttribute)attributes[0];
  16.     var actual = errorAttribute.View;
  17.     Assert.AreEqual(expected, actual);
  18. }

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:

TestContext
  1. private TestContext _testContextInstance;
  2. /// <summary>
  3. /// Gets or sets the test context which provides
  4. /// information about and functionality for the current test run.
  5. ///</summary>
  6. public TestContext TestContext
  7. {
  8.     get { return _testContextInstance; }
  9.     set { _testContextInstance = value; }
  10. }

Next, I need to map the web.config file. That seemed to be very tricky:

CreateTestFileMap
  1. private WebConfigurationFileMap CreateTestFileMap()
  2. {
  3.     var fileMap = new WebConfigurationFileMap();
  4.     var virtualDirectoryMapBase = new VirtualDirectoryMapping(TestContext.TestDeploymentDir, true, "web.config");
  5.     fileMap.VirtualDirectories.Add("/", virtualDirectoryMapBase);
  6.     return fileMap;
  7. }

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.

Code Snippet
  1. [TestCategory("Build"), TestMethod]
  2. public void CustomErrors_Are_On()
  3. {
  4.     // Arrange
  5.     var expected = CustomErrorsMode.On;
  6.     var mappedFile = CreateTestFileMap();
  7.     var config = WebConfigurationManager.OpenMappedWebConfiguration(mappedFile, "/");
  8.     var sectionGroup = config.GetSection("system.web/customErrors") as CustomErrorsSection;
  9.  
  10.     // Act
  11.     var actual = sectionGroup.Mode;
  12.  
  13.     // Assert
  14.     Assert.AreEqual(expected, actual);
  15. }

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…


Posted

in

by

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.