views:

46

answers:

3

I just created an action filter that I want to apply to nearly all of my controllers (including any new ones that are introduced later on).

I figure a really useful unit test would be one that cycles through each controller and verifies that if certain criteria are met, then the action filter will impact the result.

Is it wise to create a unit test that hits multiple controllers? Can anyone share code from a similar test that has proven useful?

EDIT: Just realized that testing an action filter might be problematic. Still, if you have thoughts to share on mass testing of controllers...

+1  A: 

Since you are most likely going to write unit tests for each controller anyway, you could always just have a unit test base class that tests the action filter. Any controller test that uses the action filter would inherit from this class to also test the action filter.

Todd
+1  A: 

I'd say at that point you are testing the infrastructure. If you want to check the filters are applied in the methods you expect, then use reflection + match a list of methods you expect to be matched.

Maybe you do want to check that the methods have a certain signature, the above would work for that as well.

If you want to test the action filter, go directly against it. Maybe what you really need is making sure different results/models work with the filter.

eglasius
+2  A: 

It is not recommended to test more than one thing at a time in tests.

You should also avoid logic in tests (switch, if, else, foreach, for, while) as the test is less readable and possibly introduces hidden bugs.

Many simple, readable, and therefore maintainable tests that are only testing one thing each are far preferable to one test with a lot of complexity.

RESPONSE TO YOUR EDIT

Testing filters can be achieved by separating the filter from the attribute. Here is an example: The LoadMembershipTypeListFilter class has the 'seams' needed to use test fakes. This is where your logic in your filter is that is to be tested.

public class LoadMembershipTypeListFilter : IActionFilter
{
    private IMembershipTypeProvider _provider;
    private IMembershipTypeAdminMapper _mapper;

    public LoadMembershipTypeListFilter(IMembershipTypeProvider provider, IMembershipTypeAdminMapper mapper)
    {
        _provider = provider;
        _mapper = mapper;
    }

    ....
}

And the attribute here uses the filter: (and your controller uses the attribute)

public class LoadMembershipTypeListAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var filter = new LoadMembershipTypeListFilter(IocResolve.Resolve<IMembershipTypeProvider>(), IocResolve.Resolve<IMembershipTypeAdminMapper>());
        filter.OnActionExecuting(filterContext);
    }
}
CRice
+1 for testability example.
Wyatt Barnett