On a project I'm working on, I'm finally to the point where I'm writing SpecFlow feature tests for a part of the project.
But, one small problem - there's an Authorization filter in our app that I need to invoke for some of the tests.
The authorization filter looks a bit like this (much redaction here)
public class Authorization : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
if(filterContext == null
|| filterContext.Controller == null
|| filterContext.Controller.ControllerContext == null)
throw new ArgumentException("Incomplete filter context.");
if(! filterContext.Controller.ControllerContext.IsChildAction)
{
if(filterContext.RequestContext == null
|| filterContext.RequestContext.HttpContext == null
|| filterContext.RequestContext.HttpContext.Request == null
|| filterContext.RequestContext.HttpContext.Request.Url == null)
throw new ArgumentException("Incomplete request in filter context.");
// SNIP: Authorization checks and activities.
// This one line is a bit tricky to mock...
HttpRequestBase request = filterContext.HttpContext.Request;
// SNIP: Other activities that come after
}
}
// SNIP: Other supporting methods that don't pertain to the problem domain.
}
...And in my feature test, I'm trying to invoke it in a special Given step:
[Given(@"I am logged in as (.*)")]
public void GivenIAmLoggedInAsX(string userId)
{
_controller = new SpecificController();
_controller.ControllerContext = new ControllerContext(new HttpContextMock(), new RouteData(), _controller);
Authorization authorize = new Authorization();
AuthorizeContext authContext = new AuthorizationContext(_controller.ControllerContext);
authorize.OnAuthorization(authContext);
// SNIP: Other activities that don't pertain to the question.
}
...This didn't work, by way of generating many NotImplementedExceptions
on the test cases that I am building up.
After asking my team, someone mentioned the ControllerActionInvoker
class in MVC. Sadly the MS Documentation is a bit shoddy on details, such as how best to employ it at all.
Also, StackOverflow also failed me in my attempts to figure out how to use a ControllerActionInvoker. The WayBack Machine didn't help much, either.
I tried a couple of different ways as interim measures that yielded no results and lots of frustration.
Question: I absolutely need to invoke this filter in the feature testing I am working with, and the direct approach isn't working. What is the best way to invoke a filter for a feature test?
Side-note: The whole MVC filtering system is unexplored territory for me, so there's a lot I don't know. In your answer, assume I know nearly nothing, because that's probably accurate, even with the research I've done on ways to do this.
Alt Implementation #1
I found my original example uses an obsolete constructor; there is a 2-arg constructor that is recommended instead. So, I used it to no good effect. Here's what it looks like (still the direct approach:)
[Given(@"I am logged in as (.*)")]
public void GivenIAmLoggedInAsX(string userId)
{
_controller = new RequestFormController();
_controller.ControllerContext = new ControllerContext(new HttpContextMock(), new RouteData(), _controller);
Authorization authorize = new Authorization();
MethodInfo method = typeof (MyController).GetMethod("MyAction");
ControllerDescriptor controllerDescriptor = new ReflectedControllerDescriptor(typeof(MyController));
ActionDescriptor actionDescriptor = new ReflectedActionDescriptor(method, "MyAction", controllerDescriptor);
AuthorizationContext authContext = new AuthorizationContext(_controller.ControllerContext, actionDescriptor);
authorization.OnAuthorization(authContext);
// SNIP: Unrelated code.
}
From my experience, I would suggest testing the functionality of OnAuthorization using a unit or integration test.
I would use Specflow along with a web driver to test the scenario purely from a browser context i.e. testing the feature just by interacting with the website. Hence your "given" should just use a web driver to verify that a user has logged in as "userId" e.g. by checking for the presence of their name on the web page or something similar.