Mocking HttpServletRequest to test Acegi-JSF

I’m a big fan of mock objects and enjoy playing with them. When working on the new release of my acegi-jsf components, I’ve written a couple of tests to check some stuff but realized that it was impossible to test the heart of the whole thing. The component Authorize has a dependendency to an IAuthenticationMode, there are 3 implementations of this interface; AllAuthenticationMode, AnyAuthenticationMode, NotAuthenticationMode each corresponds to component attributes ifAllGranted, ifAnyGranted, ifNotGranted. IAuthenticationMode has one method “isUserInRole(String roles, HttpServletRequest);”, each mode implements in their own way. Talking in patterns vocabulary; Strategy Pattern. Here is the IAuthenticationMode and the AllAuthenticationMode code(Other two are similiar).


IAuthenticationMode.java

  
  
  

    public interface IAuthenticationMode {
  public boolean isUserInRole(String roles, HttpServletRequest request);
}
  


AllAuthenticationMode.java

  
  
  

    public class AllAuthenticationMode implements IAuthenticationMode {

  public boolean isUserInRole(String roleList, HttpServletRequest request) {
    String [] roles = AcegiJsfUtils.parseRoleList(roleList);
    boolean isAuthorized = false;
    
    for (int i = 0; i < roles.length; i++) {
      if(request.isUserInRole(roles[i])) {
        isAuthorized = true;
      else {
        isAuthorized = false;
        break;
      }
    }
    return isAuthorized;
  }
}
  


Component’s class name is Authorize, this is the one with a dependency to an IAuthenticationMode and a HttpServletRequest. AuthenticationMode is set using the Tag class of the component. When component is called to encode it’s children, it checks whether the user satisfies the role requirements or not. If so, then it simply encodes the children. Following is the related part of Authorize.java.


Authorize.java

  
  
  

    public class Authorize extends UIComponentBase {
  private IAuthenticationMode authenticationMode;
  
  private HttpServletRequest request;
  
  public void encodeChildren(FacesContext contextthrows IOException {
    if (isUserInRole(getRoles())) {
      for (Iterator iter = getChildren().iterator(); iter.hasNext();) {
        UIComponent child = (UIComponentiter.next();
        encodeRecursive(context, child);
      }
    }
  }
  
  public boolean isUserInRole(String roles) {
    return getAuthenticationMode().isUserInRole(roles, getRequest());
  }
  
  public IAuthenticationMode getAuthenticationMode() {
    return authenticationMode;
  }

  public void setAuthenticationMode(IAuthenticationMode authenticationMode) {
    this.authenticationMode = authenticationMode;
  }
  
  private HttpServletRequest getRequest() {
    if(request == null)
      request = (HttpServletRequestFacesContext.getCurrentInstance().getExternalContext().getRequest();
    return request;
  }
  
  public void setRequest(HttpServletRequest request) {
    this.request = request;
}
  


So lets get back to the title of this entry, Mocking HttpServletRequest to test Acegi-JSF. If you check out the IAuthenticationMode implementations, each make a call to HttpServletRequest.isUserInRole(); method which was already wrapped by Acegi. So in order to test these implementations I’ve mocked HttpServletRequest and checked the outcomes. Here is the test of AllAuthenticationMode;


AuthorizeTester.java

  
  
  

    public class AuthorizeTester extends MockObjectTestCase {

  private Authorize authorize;
  
  private IAuthenticationMode authenticationMode;
  
  Mock mockRequest;
  
  private String roles;
  
  public void setUp() {
    authorize = new Authorize();
    mockRequest = new Mock(HttpServletRequest.class);
    authorize.setRequest((HttpServletRequestmockRequest.proxy());
    roles = "A,B, C";
  }
  
  public void testAllAuthenticationModeReturnsFalseWhenUserSatisfiesFirstTwoRolesButNotTheLastOne() {
    authorize.setAuthenticationMode(new AllAuthenticationMode());
    mockRequest.expects(once()).method("isUserInRole").with(eq("A")).will(returnValue(true));
    mockRequest.expects(once()).method("isUserInRole").with(eq("B")).will(returnValue(true));
    mockRequest.expects(once()).method("isUserInRole").with(eq("C")).will(returnValue(false));
    boolean isUserInRole = authorize.isUserInRole(roles);
    assertEquals(isUserInRole, false);
  }
  
  public void testAllAuthenticationModeReturnsTrueWhenUserSatisfiesAllOfTheRoles() {
    authorize.setAuthenticationMode(new AllAuthenticationMode());
    mockRequest.expects(once()).method("isUserInRole").with(eq("A")).will(returnValue(true));
    mockRequest.expects(once()).method("isUserInRole").with(eq("B")).will(returnValue(true));
    mockRequest.expects(once()).method("isUserInRole").with(eq("C")).will(returnValue(true));
    boolean isUserInRole = authorize.isUserInRole(roles);
    assertEquals(isUserInRole, true);
  }
}
  

The role list is “A,B, C”, I test the condition where the ifAllGranted is supplied with this list. Then I set expectations on request for each of the roles. For example, in first test, user is in role A,B but not in C. Also as a test lunatic myself, I did not forget to write the simple test of the function that takes a role list seperated with commas and whitespaces and returns a string array whose elements will be checked in isUserInRole(String role). Yes this is an easy test but I had a lot of pain after I’ve missed a test case.


AcegiJsfUtils.java

  
  
  

    public class AcegiJsfUtils {

  public static String[] parseRoleList(String roles) {
    String [] roleArray =  roles.split(",");
    for (int i = 0; i < roleArray.length; i++) {
      roleArray[i= roleArray[i].trim();
    }
    return roleArray;
  }
}
  

AcegiJsfUtilsTester.java

  
  
  

    public class AcegiJsfUtilsTester extends TestCase {

  public void testRoleListParsingRunsOkWhenThereAreWhitespacesEverywhere() {
    String roleString = "ROLE_A ,   ROLE_B ,     ROLE_C";
    String [] roles = AcegiJsfUtils.parseRoleList(roleString);
    assertEquals(roles.length, 3);
    assertEquals(roles[0],"ROLE_A");
    assertEquals(roles[1],"ROLE_B");
    assertEquals(roles[2],"ROLE_C");
  }
}
  

There are more tests, I’ve just posted some of them as an example but all can be found at myFaces jsf-comp repository at sourceforge. In addition as I mentioned before I’ve refactored my code in order to make it suitable for testing, I believe this is yet another advantage that testing brings to your code. To end with something cool; “Testing leads to better code, not just safer”.

One Response to Mocking HttpServletRequest to test Acegi-JSF

  1. Jacob says:

    I was surprised at how straightforward it was to mock up JSF, I have a FaceletTestCase which allows me to play around with tree creation and rendering/testing on the fly. It’s made development of that framework really easy (sort of ;-))

%d bloggers like this: