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);
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 });
T result = exp.Compile()();
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;
}
}