Geeks With Blogs

News INETA Community Speakers Program
GeeksWithBlogs.net: WTFNext's hosting!

View Stacy Vicknair's profile on LinkedIn


WTF Next? Dev ramblings from a master of nothing.

When testing in ASP.NET MVC3, one of the common elements you might want to test is authorization. Although the framework does most of the heavy lifting for ASP.NET Membership and authorization it is still worthwhile to be able to write a test to show that the proper Authorization tag is in place.

You might think that it’s as easy as calling the method on the controller with a proper context, but that’s not the case. When you call the methods directly on the controller the authorizations are skipped. These authorizations are handled by the ActionInvoker when the MVC application runs, so in order to test this via MVC itself would take a lot of cruft. Since we trust that ASP.NET MVC is doing its job correctly it is easier to simply test for the presence of the attributes.

Since this is such a common task I ventured forth to create an extension method that will accomplish exactly what I want with the API I want. Using a lambda syntax most of us are familiar with from mocking frameworks, the final product yields a test method like the following:

   1: <TestMethod()>
   2: Public Sub Register_WhenUserIsInAdministratorRole_ShouldBeAuthorized()
   3:     'Arrange
   4:     Dim target = New AccountController()
   5:  
   6:     'Assert
   7:     target.AssertRoleIsAuthorizedForAction(Sub(a) a.Register(New RegisterModel()), "Administrator")
   8: End Sub

 

Simply pass in a lambda of the action you are attempting to test along with the role you expect authorization to be successful for. The extension method code is as follows:

   1: <Extension()>
   2: Public Sub AssertRoleIsAuthorizedForAction(Of T As Controller)(ByVal controller As T,
   3:     ByVal expression As Expression(Of Action(Of T)), role As String)
   4:  
   5:     'Arrange
   6:     'Get method from expression
   7:     Dim callExpression = TryCast(expression.Body, MethodCallExpression)
   8:     If callExpression Is Nothing Then
   9:         Throw New ArgumentException("Could not determine method from expression", "expression")
  10:     End If
  11:  
  12:     'Act
  13:     Dim roles = callExpression.Method.GetCustomAttributes(GetType(AuthorizeAttribute), inherit:=True) _
  14:         .Cast(Of AuthorizeAttribute)() _
  15:         .Where(Function(a) Not String.IsNullOrEmpty(a.Roles)) _
  16:         .SelectMany(Function(a) a.Roles.Split(",")) _
  17:         .ToList()
  18:  
  19:     'Assert
  20:     Assert.IsTrue(roles.Contains(role))
  21: End Sub

The method takes the given lambda and extracts the method. Then the AuthorizeAttributes for the method that include roles are split into a list of roles. Finally we assert that the list of roles contains our role in question.

In C#:

   1: [TestMethod]
   2: public void Register_WhenUserIsInAdministratorRole_ShouldBeAuthorized()
   3: {
   4:     //arrange
   5:     var accountController = new AccountController();
   6:  
   7:     //assert
   8:     accountController.AssertRoleIsAuthorizedForAction(ac => ac.Register(new RegisterModel()), "Administrator");
   9: }
   1: public static void AssertRoleIsAuthorizedForAction<T>(this T controller, 
   2:     Expression<Action<T>> expression, string role) where T : Controller
   3: {
   4:     //Arrange
   5:     //Get method from expression
   6:     var callExpression = expression.Body as MethodCallExpression;
   7:     if(callExpression == null)
   8:         throw new ArgumentException("Could not determine method from expression", "expression");
   9:  
  10:     //Act
  11:     var roles = callExpression.Method.GetCustomAttributes(typeof(AuthorizeAttribute),true)
  12:         .Cast<AuthorizeAttribute>()
  13:         .Where(a => !string.IsNullOrEmpty(a.Roles))
  14:         .SelectMany(a => a.Roles.Split(','))
  15:         .ToList();
  16:  
  17:     //Assert
  18:     Assert.IsTrue(roles.Contains(role));
  19: }

 

References:
http://stackoverflow.com/questions/669175/unit-testing-asp-net-mvc-authorize-attribute-to-verify-redirect-to-login-page
http://darioquintana.com.ar/blogging/2009/05/23/aspnet-mvc-testing-a-custom-authorize-filters/

Posted on Tuesday, August 23, 2011 1:02 AM How-To | Back to top


Comments on this post: Unit Testing Role-based Authorization in ASP.NET MVC 3

No comments posted yet.
Your comment:
 (will show your gravatar)


Copyright © Stacy Vicknair | Powered by: GeeksWithBlogs.net