How to unit test ActionFilterAttribute
Here is a real life example, where I also access the method info and params inside the action filter attribute:
Suppose I have a Controller Method with ActionAttribute like this:
public class HomeController : Controller
{
...
[FeatureFlagActionAtrribute("user", new String[] { "Feature1" })]
public IActionResult DoSomethingWithFilterAction(String user)
{...}
}
The http call would be something like this:
/Home/DoSomethingWithFilterAction?user="user1"
Now, I want to test the ActionAttribute FeatureFlagActionAtrribute in such a context.
If you would apply above suggestion to this example, it would look like this (worked for me, at least)
var methodInfoDoSomethingWithFilterAction = typeof(HomeController).GetMethod(nameof(HomeController.DoSomethingWithFilterAction));
var httpContext = new DefaultHttpContext();
var routeData = new RouteData();
FeatureFlagActionAtrribute FeatureFlagActionAtrributeFilter = methodInfoDoSomethingWithFilterAction.GetCustomAttribute<FeatureFlagActionAtrribute>();
ActionDescriptor actionDescriptor = new ControllerActionDescriptor()
{
ActionName = methodInfoDoSomethingWithFilterAction.Name,
ControllerName = typeof(FeatureFlagTest).Name,
DisplayName = methodInfoDoSomethingWithFilterAction.Name,
MethodInfo = methodInfoDoSomethingWithFilterAction,
};
ActionContext actionContext = new ActionContext(httpContext, routeData, actionDescriptor) ;
var homeController = new HomeController();
var attribute = new FeatureFlagActionAtrribute("user", new string[] { "feature1" });
IDictionary<string, object> actionArguments = new Dictionary<string, object>
{
["user"] = "user1"
};
var filterMetadata = new List<IFilterMetadata>() { featureFlagActionAtrributeFilter };
ActionExecutingContext actionExecutedContext = new
ActionExecutingContext(actionContext, filterMetadata, actionArguments, homeController);
attribute.OnActionExecuting(actionExecutedContext);
Then inside the ActionFilterAttribute:
public override void OnActionExecuting(ActionExecutingContext context)
{
ControllerActionDescriptor actionDescriptor = (ControllerActionDescriptor)context.ActionDescriptor;
Debug.Print($"2. @Before Method called {actionDescriptor.ControllerName}Controller.{actionDescriptor.ActionName}");
var controllerName = actionDescriptor.ControllerName;
var actionName = actionDescriptor.ActionName;
IDictionary<object, object> properties = actionDescriptor.Properties;
ParameterInfo[] paramsOfMethod = actionDescriptor.MethodInfo.GetParameters();
var fullName = actionDescriptor.DisplayName;
var paramNameForKeyOfFeature = ParamNameForKeyOfFeature;
var arguments = context.ActionArguments;
Create an instance of the context pass it to the filter and assert the expected behavior
For example
[TestClass]
public class ValidateModelAttributeTest {
[TestMethod]
public void Invalid_ModelState_Should_Return_BadRequestObjectResult() {
//Arrange
var modelState = new ModelStateDictionary();
modelState.AddModelError("", "error");
var httpContext = new DefaultHttpContext();
var context = new ActionExecutingContext(
new ActionContext(
httpContext: httpContext,
routeData: new RouteData(),
actionDescriptor: new ActionDescriptor(),
modelState: modelState
),
new List<IFilterMetadata>(),
new Dictionary<string, object>(),
new Mock<Controller>().Object);
var sut = new ValidateModelAttribute();
//Act
sut.OnActionExecuting(context);
//Assert
context.Result.Should().NotBeNull()
.And.BeOfType<BadRequestObjectResult>();
}
}