How can I do a Unit test of the HandleError attribute behavior for a controller method?

I am trying to check the behavior of my ASP.Net MVC application when an unexpected error occurs. In particular, I am trying to verify that the user is redirected to a page with an error specific to my application. The problem I am facing is that I cannot verify the behavior of the controller method as expected.

For my usual behavior tests, I create a business rule object object and pass it to my controller, and then test the ViewResult from the controller method that I want to test. This works great for my purposes, when everything works as expected. However , when I throw an exception to the business rule method, the exception is thrown using the result of the controller method, and not processed (the controller method has the "HandleError" attribute) by the controller, so that the corresponding ViewResult for the error returned by my page.

Is there a way to test the behavior of the HandleError attribute this way? Or am I completely wrong about this? I understand that I can use Selenium (testing in a browser that would hit the actual server) to test the behavior in a real browser, but mocking these types of tests allows me to do this faster and with much less overhead ...

Sample test code:

// WidgetController.Index() makes a call to GetWidgets to retrieve a // List<Widget> instance. // this works as expected since the appropriate ViewResult is returned // by the controller public void TestWidgetControllerIndex_NoResultsFound() { var mockBR = new Mock<IBusinessRules> { CallBase = true }; mockBR.Setup(br=>fr.GetWidgets()).Returns(new List<Widget>()); WidgetController controller = new WidgetController(mockBR.Object); ViewResult result = (ViewResult)controller.Index(); Assert.AreEqual("Index", result.ViewName); Assert.AreEqual(0, ((WidgetIndexViewData)result.ViewData.Model).Widgets.Count); } // this test is unable to reach the assertion statements due to the problem // outlined above. WidgetController.Index has the HandleError attribute // properly applied and the behaviour via the interface is as expected public void TestWidgetControllerIndex_BusinessRulesExceptionEncountered() { var mockBR = new Mock<IBusinessRules> { CallBase = true }; mockBR.Setup(br=>fr.GetWidgets()).Throws<ApplicationException>(); WidgetController controller = new WidgetController(mockBR.Object); ViewResult result = (ViewResult)controller.Index(); // The ApplicationException thrown by the business rules object bubbles // up to the test through the line above. I was expecting this to be // caught and handled by the HandleError filter (which would then let // me verify the behaviour results via the assertion below).. Assert.AreEqual("Error", result.ViewName); } 

I would appreciate any suggestions as to what I might be doing wrong, or I am just approaching it from a completely wrong direction. I proceed from the assumption that testing at the controller method level is an appropriate way to go here from where the HandleError attribute is applied .. (If I need to test at the application level, can this be done using similar ones and not use something like Selenium?)

Update I concluded that I should not test the functionality associated with the HandleError attribute for each controller action. I really don't care what he does, I just want to make sure that the error is being handled (from my point of view, is her own code or MVC libraries different, this is the functionality I want to check).

What I ended up with is transferring my actions with the controller to try / catch blocks to force the Error view to be returned as a result of the method (and not the ErrorHandler attribute, which catches the error as it leaves the method). Thus, I can state in my unit tests that the error is properly handled with the appropriate feedback. I am not very happy with the extra length that my controller methods add, but this allows me to provide the user with an individual error message (I use the extension method to display feedback and complete the registration). (So ​​there are pros and cons to the try / catch approach for sure).

I am not 100% sure that this is the cleanest way to go, but it reaches my goal - to verify that errors are handled by control test blocks (quickly), and not to run tests in the browser (slow). So for now, this is good enough until I find a cleaner solution. I decided to offer generosity if someone encounters a similar problem and find a better solution.

+6
asp.net-mvc selenium nunit
source share
2 answers

I think you cannot unit test this. And you do not want this. You can verify that the expected exception is thrown by the controller method. Using reflection, you can verify that the action or controller has an attribute that you expect from it, and that the attribute has certain expected property values. However, the task of catching the exception and executing the attribute is the behavior of the structure, not the code. Generally speaking, you should not test code that is not yours (framework).

+6
source share

Yes, I agree with Tim. What you are describing is an integration test. The behavior of HandleErrorAttribute depends on the behavior of ASP.NET, for example, regardless of whether the user errors are set to web.config.

For your unit test, you can simply use reflection to make sure the attribute is present.
The MVC team has unit tests for HandleErrorAttribute, so you don’t need to write them. :) Then just manually check your action to make sure the behavior you want. As long as you never change / delete an attribute, the behavior should not change.

If you want to automate the integration test, you can use Watin or Selenium to automate the real browser request to make sure that the behavior of your application does not change.

+1
source share

All Articles