views:

464

answers:

1

I've overridden my controller's OnActionExecuting method to set some internal state based on the executing filterContext. How do I test this? The method itself is protected so I assume I'll have to go higher up in the call stack.

What code do I need to test this?

I'm using mvc RC 1.

Edit: I'm also using nunit.

Thanks

+3  A: 

You need to add and use a Private Accessor. Right click in your controller class and choose Create Private Accessors from the menu and add them to your test project. Once in your test project, create your controller, then create an accessor for it. The method should be available on the accessor. Here's a sample test from my own code:

/// <summary>
///A test for OnActionExecuting
///</summary>
[TestMethod()]
[ExpectedException( typeof( InvalidOperationException ) )]
public void OnActionExecutingWindowsIdentityTest()
{
    var identity = WindowsIdentity.GetCurrent();
    WindowsPrincipal principal = new WindowsPrincipal( identity );
    var httpContext = MockRepository.GenerateStub<HttpContextBase>();
    httpContext.User = principal;

    var actionDescriptor = MockRepository.GenerateStub<ActionDescriptor>();

    RouteData routeData = new RouteData();

    BaseController controller = new BaseController();
    BaseController_Accessor accessor = new BaseController_Accessor( new PrivateObject( controller ) );
    ControllerContext controllerContext = MockRepository.GenerateStub<ControllerContext>( httpContext, routeData, controller );

    ActionExecutingContext filterContext = new ActionExecutingContext( controllerContext, actionDescriptor, new Dictionary<string, object>() );

    accessor.OnActionExecuting( filterContext );

}

EDIT: If you aren't using MSTest for your unit tests, you may have to generate the accessors by hand. Essentially, you make a wrapper class that exposes the private/protected methods of the class under test via equivalent public methods, pass an instance of the class under test to the wrapper, and then use reflection from the wrapper class to invoke the private/protected method on the class under test.

   public class MyClass
   {
       protected void DoSomething( int num )
       {
       }
   }

   public class MyClass_accessor
   {
       private MyClass privateObj;

       public MyClass_accessor( MyClass obj )
       {
           this.privateObj = obj;
       }

       public void DoSomething( int num )
       {
           MethodInfo info = privateObj.GetType()
                                       .GetMethod("DoSomething",
                                                   BindingFlags.NonPublic
                                                   | BindingFlags.Instance );

           info.Invoke(obj,new object[] { num });
       }
    }
tvanfosson
Is this MSTest specific? I'm using nunit and xunit atm.
TheDeeno
I only ask because I don't see the 'add accessor' context button and doing a google search brings me to some ms test specific stuff.
TheDeeno
Yes, I think it is. I suppose that it requires at least VS Pro for it to be there. You can create one by hand though and use reflection to invoke the appropriate method on the underlying private object.
tvanfosson
There's nothing really magic about the accessors added via MSTest, they just use reflection. They are nice in that you don't have to generate all the code. I've given an example in my answer. Note that you could also invoke the method directly in your tests via reflection, but it may violate DRY.
tvanfosson
Thanks for the help. I have VS Pro. I was able to generate accessors by right clicking and going to "Create Unit Tests..." and select the private method I wanted to test. This created an MSTest project with the appropriate accessor generated.
TheDeeno
Rather than go through those steps each time though I'll just make the accessors by hand like you described. Thanks for the example.
TheDeeno