views:

343

answers:

3

A well-known benefit of MVC is its suitablility for Test Driven Development (TDD) because you can directly call your controller actions from your test methods.

How can you test the combination of a controller action with a ActionFilter attribute (using OnActionExecuted to modify the ActionResult returned by the Action)? If I just call the Action, it returns the ActionResult from the action, but the filter attribute is never invoked. I think maybe you can get it by Controller.ActionInvoker.InvokeAction(controllerContext, "ActionName"), but you have to accurately mock so much of the controllerContext to make it work that it's a real pain.

Has anyone successfully done this?

+1  A: 

I think you'll be better off testing controller and attribute (filter) in isolation, and then assert that there's indeed an attribute on a specific controller action (method).

Anton Gogolev
+1 for testing each individually and then asserting the action has the attribute.
Mark
+1  A: 

Unit testing is about single units not a combination of them

Unit tests are about testing a single unit of functionality/process/work. You should test attribute separately to controller action.

  1. You should first test that your controller action is working as expected and returning expected action results.

  2. Then test that your attribute does what it should = convert action results as expected.

Two separate unit tests, not a single one.

Robert Koritnik
+1 ...but I would also test that your controller action has that attribute, as Anton said.
Mark
Action filters are separate code that should not be required on controller actions. Testing that certain controller actions have attributes attached to them is more part of **integration testing** than unit testing I guess.
Robert Koritnik
@Robert I agree you shouldn't need to execute that code to test the controller, but if you have a requirement that says this action is to be logged, you are testing that this requirement is met by the presence of that action....not that the action actually does what it says it does.
Mark
@Mark: I fully understand what you mean and I'd probably do this in the same way and include it in my unit test scenario, but logging by itself is an integration matter. Because log is usually a separate system (just like DB is) and it would slow unit tests down. Unit test are supposed to be very fast. How would you assert that a certain log message has been logged anyways?
Robert Koritnik
@Robert Assuming the action filter we added was just logging each time the action was called (just an arbitrary action filter example), we would assert the action method was attributed with the correct action. We would then have a separate battery of tests around that action that it calls the correct logging abstractions. We then have implementations of those logging abstractions that get tested to makes sure they do what they do. ...but when testing the controller, nothing really gets logged to a db.
Mark
A: 

We do something similar when we test our DataAnnotation validations. We test the property model for the correct attributes using reflection. When we test our controllers, we just set the model validity manually. As both Robert and Anton have mention, your test should expose one specific assertion on one specific class.

Mark