65.9K
CodeProject is changing. Read more.
Home

OnActionExecuting and OnActionExecuted in MVC unit test

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (1 vote)

Jul 20, 2013

CPOL
viewsIcon

19508

Here is a simple example of how to automatically call them when the main controller method is called.

When testing MVC controllers, OnActionExecuted and OnActionExecuting functions are not get called. Here is a simple example of how to automatically call them when the main controller method is called. All you have to do is wrap the controller call into the Invoke() function.

[TestClass]
public class MyTest
{
    [TestMethod]
    public void TestSomething()
    {
        var actionResult = Invoke(() => new MyController().DoSomething());      
    }

    protected static T Invoke<T>(Expression<Func<T>> exp) where T : ActionResult
    {
        var methodCall = (MethodCallExpression) exp.Body;
        var method = methodCall.Method;
        var memberExpression = (MemberExpression)methodCall.Object;

        Expression<Func<Object>> getCallerExpression = 
          Expression<Func<Object>>.Lambda<Func<Object>>(memberExpression);
        Func<Object> getCaller = getCallerExpression.Compile();
        var ctrlr = (Controller)getCaller();

        ControllerDescriptor controllerDescriptor = new ReflectedControllerDescriptor(ctrlr.GetType());
        ActionDescriptor actionDescriptor = 
          new ReflectedActionDescriptor(method, method.Name, controllerDescriptor);

        // OnActionExecuting

        var rc = new RequestContext();
        ctrlr.ControllerContext = new ControllerContext(rc, ctrlr);
        var ctx1 = new ActionExecutingContext(ctrlr.ControllerContext, 
          actionDescriptor, new Dictionary<string, object>());
        MethodInfo onActionExecuting = ctrlr.GetType().GetMethod(
          "OnActionExecuting", BindingFlags.Instance | BindingFlags.NonPublic);
        onActionExecuting.Invoke(ctrlr, new object[] { ctx1 });

        // call controller method

        T result = exp.Compile()();

        // OnActionExecuted

        var ctx2 = new ActionExecutedContext(ctrlr.ControllerContext, 
          actionDescriptor, false, null){Result = result};
        MethodInfo onActionExecuted = ctrlr.GetType().GetMethod(
          "OnActionExecuted", BindingFlags.Instance | BindingFlags.NonPublic);
        onActionExecuted.Invoke(ctrlr, new object[] { ctx2 });

        return (T)ctx2.Result;
    }
}