Question

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.
}
Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top