Mathias Brandewinder on .NET, F#, VSTO and Excel development, and quantitative analysis / machine learning.
by Mathias 12. December 2010 17:00

I recently began playing with ASP.NET MVC (never too late), and so far I really enjoy it. One aspect I really appreciate is its testability – I can write fairly straightforward unit tests to verify that the application behaves as I believe it should, as well as make sure I understand what is going on.

One point which got me stumped was how to test for authorization. A controller, or some of its methods, can be decorated with the attribute [Authorize], restricting users who can access the method by role or name. In the default ASP.NET MVC 2 template, when a user isn’t authorized to a specific area, he gets re-directed to the LogOn method on the AccountController.

So far so good. However, I ran into unexpected issues when I attempted to unit test that. Suppose there are two roles in our web application, Chicken and Pigs, and that we have a Controller that leads to a pigs-only area of the web site:

[Authorize(Roles = "Pig")]
public class PigsOnlyController : Controller
{
   public ActionResult Index()
   {
      return View("Index");
   }
}

My first thought was to mock the ControllerContext and do something along these lines:

[Test]
public void OnlyPigsShouldAccessIndex()
{
   var context = new Mock<ControllerContext>();
   var userName = "PIG";
   context.SetupGet(p => p.HttpContext.User.Identity.Name).Returns(userName);
   context.SetupGet(p => p.HttpContext.Request.IsAuthenticated).Returns(true);
   context.Setup(p => p.HttpContext.User.IsInRole("Pig")).Returns(true);

   var controller = new PigsOnlyController();
   controller.ControllerContext = context.Object;

   // check what controller.Index() returns
}

However, while the web application itself behaved properly (Users in the Pig role get to the Index page, whereas Chicken get redirected to the Logon page), the test wasn’t doing what I expected: both Pigs and Chicken were happily reaching the Pigs-Only area.

As is often the case, I found out why on StackOverflow; the reason is that the re-direction is not the responsibility of the Controller. If the controller is properly decorated, the Index method won’t even be invoked, and where the call gets redirected to is handled in a different part.

So how do you unit test this behavior? In this case, we trust the framework to handle the redirection, so the only functionality we need to ascertain is that the Controller has the proper attribute.

Instead of validating the redirection, we can verify that the Controller class has an Authorize attribute, with the proper roles specified:

[Test]
public void ControllerShouldAuthorizePigsButNotChicken()
{
   var information = typeof(PigsOnlyController);
   var attributes = information.GetCustomAttributes(typeof(AuthorizeAttribute), false);
   Assert.AreEqual(1, attributes.Length);

   var authorization = attributes[0] as AuthorizeAttribute;
   var authorizedRoles = authorization.Roles;

   var roles = authorizedRoles.Split(',');
   Assert.IsTrue(roles.Contains("Pig"));
   Assert.IsFalse(roles.Contains("Chicken"));
}

I am not totally happy with the hard-coded strings “Pig” and “Chicken” in the test, but I don’t see a way around it; maybe it’s a sign that this test is more of an integration test than a unit test? If you know of a better way to test for that aspect, I am all ears!

Comments

2/18/2011 4:23:40 PM #

trackback

Codebix.com - Your post is on Codebix.com

This post has been featured on Codebix.com. The place to find latest articles on programming. Click on the url to reach your post's page.

Codebix.com | Reply

6/30/2012 11:57:55 AM #

pingback

Pingback from cutebeachvacationideas.sims2dl.com

Canada: Kleenex hand sanitizer recalled over bacterial contamination | Cute Beach Vacation Ideas

cutebeachvacationideas.sims2dl.com | Reply

4/30/2013 3:18:55 AM #

Mark

I have been using java struts for a long time. Buy eventually found out to too bulky to handle. On my recent php websites I built my own MVC framework with database oriented url routing. Being lightweight and ability to reference the controller from the view object I can actually shift some of the database queries that give huge results until the view is actually rendered. The url_router class is actully database driven and it is the first thing invoked and decides whether to reroute or invoke a controller and execute any method on it. When using a MVC architecture, there is going to be chicken-or-egg problem. But finding the right tradeoff is the key thing. That's why I built my own MVC architecture.

Mark United Kingdom | Reply

Add comment




  Country flag

biuquote
  • Comment
  • Preview
Loading



Comments

Comment RSS