Testing JSF without the Container

Thanks to the AbstractJsfTestCase, Test Driven JSF Development has become my favorite hobby nowadays. At past before Shale, we’ve created our own static mock library containing 4-5 mock implementations of classes like FacesContext, Application in our project. But Shale Test Framework is almost an actual mock implementation of the JSF spec. I’ve first used it when I was writing the tests of the extended UISelectItems of MyFaces(EasySI) and absolutely fascinated by the features. It basically gives you everything you need. In order to demonstrate features I’ve written a custom JSF component as an example and test it with the test framework.

The component’s name is InputDate and it’s a simple input text that can be used for binding dates. It only accepts the “dd.MM.yyyy” type of pattern and if the entered date is after today’s date, mark’s itself at invalid. This is just a simple example, of course there are fancy date components like InputCalendar, InputDate(I’ve fixed the forceId issue by the way) in MyFaces for actual usage.

  
    
    

package inputdate;

import java.io.IOException;
import java.util.Date;

import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;

public class InputDate extends UIInput {

  public InputDate() {
    super();
    setRendererType(null);
  }

  public void decode(FacesContext context) {
    String clientId = getClientId(context);
    String submittedValue = (Stringcontext.getExternalContext().getRequestParameterMap().get(clientId);
    setSubmittedValue(submittedValue);
    setValid(true);
  }

  public void validate(FacesContext context) {
    super.validate(context);
    if (getLocalValue() != null) {
      Date date = (DategetLocalValue();
      Date now = new Date();
      if (now.compareTo(date0)
        setValid(false);
    }
  }

  public void encodeEnd(FacesContext contextthrows IOException {
    ResponseWriter writer = context.getResponseWriter();
    writer.startElement(“input”this);
    writer.writeAttribute(“id”, getClientId(context)“id”);
    writer.writeAttribute(“name”, getClientId(context)null);
    if (getValue() != null)
      writer.writeAttribute(“value”, getConverter().getAsString(context,
          this, getValue())“value”);
    else
      writer.writeAttribute(“value”“”“value”);

    writer.endElement(“input”);
  }

}      

As you see it’s quite simple, no renderer, just renders an input text and only used for dates. In a page it can be used like;

 <barca:inputDate id=”inputDate1″ value=”#{SomeBean.birthDate}”>
                    <f:convertDateTime pattern=”dd.MM.yyyy”/>
   </barca:inputDate>

Here comes the fun part, the tester;

  
    
    

package inputdate.test;

import javax.faces.component.UIForm;
import javax.faces.component.html.HtmlForm;
import javax.faces.convert.DateTimeConverter;
import javax.faces.el.ValueBinding;

import inputdate.InputDate;
import inputdate.SomeBean;
import junit.framework.Test;
import junit.framework.TestSuite;

import org.apache.shale.test.base.AbstractJsfTestCase;

public class InputDateTester extends AbstractJsfTestCase {

  private InputDate inputDate;
  
  public InputDateTester(String testname) {
    super(testname);
  }
  
  public void setUp() {
    super.setUp();
    
    //create the view
    UIForm parent = new HtmlForm();
    parent.setId(“form1”);
    parent.setParent(facesContext.getViewRoot());
    inputDate = new InputDate();
    inputDate.setId(“inputDate1”);
    inputDate.setParent(parent);
    
    //set the converter
    DateTimeConverter converter = new DateTimeConverter();
    converter.setPattern(“dd.MM.yyyy”);
    inputDate.setConverter(converter);
    
    //set the value binding
    ValueBinding valueBinding = facesContext.getApplication().createValueBinding(“#{SomeBean.birthDate}”);
    inputDate.setValueBinding(“value”, valueBinding);
    facesContext.getExternalContext().getRequestMap().put(“SomeBean”new SomeBean());
  }
  
  public static Test suite() {
      return new TestSuite(InputDateTester.class);
  }
  
  public void tearDown() {
    inputDate = null;
      super.tearDown();
  }
  
  public void testSubmittedValueMustBeEqualToThePostedData() {
    facesContext.getExternalContext().getRequestParameterMap().put(“form1:inputDate1”“15.07.2000”);
    inputDate.processDecodes(facesContext);
    assertEquals(inputDate.getSubmittedValue()“15.07.2000”);
    assertNull(inputDate.getLocalValue());      //no conversion-validation yet
  }
  
  public void testConversionErrorMustOccurWhenTheInputIsNotInStatedFormat() {
    facesContext.getExternalContext().getRequestParameterMap().put(“form1:inputDate1”“ineedavacation”);
    inputDate.processDecodes(facesContext);
    inputDate.processValidators(facesContext);
    assertFalse(inputDate.isValid());
  }
  
  public void testWhenImmediateIsTrueConversionValidationTakesPlaceAtDecode() {
    facesContext.getExternalContext().getRequestParameterMap().put(“form1:inputDate1”“15.07.2000”);
    inputDate.setImmediate(true);
    inputDate.processDecodes(facesContext);      //conversion-validation
    assertNotNull(inputDate.getLocalValue());
  }
  
  public void testWhenTheEnteredDateIsLaterThanTodayValidationErrorMustOccur() {
    facesContext.getExternalContext().getRequestParameterMap().put(“form1:inputDate1”“15.07.2010”);
    inputDate.processDecodes(facesContext);
    inputDate.processValidators(facesContext);
    assertFalse(inputDate.isValid());
  }
  
  public void testSomeBeansBirthDateAttributeIsUpdatedAtUpdateModel() {
    facesContext.getExternalContext().getRequestParameterMap().put(“form1:inputDate1”“15.07.2000”);
    inputDate.processDecodes(facesContext);
    inputDate.processValidators(facesContext);
    inputDate.processUpdates(facesContext);
  &
nbsp; 
SomeBean someBean = (SomeBean)facesContext.getApplication().getVariableResolver().resolveVariable(facesContext, “SomeBean”);
    assertNotNull(someBean.getBirthDate());
  }
}      

Extending from the AbstractJsfTestCase, everything I need(FacesContext, Application, External Context, RequestMap etc.) is prepared before beginning the testing. On setup I setup a component tree is created and set a converter to the inputDate. Also a valuebinding for the SomeBean’s birth date variable. The tests are very useful to see how the component will act during request lifecycle and in a real container environment. In order to imitate it, I’ve tried to cover the component’s behaviours in different phases and cases. The phase I’ve not covered is the render response which means the output of the component. Well, first it does not suit the unit testing idea well and does’nt seem to be possible for now. The workaround is to use a library like htmlunit and run the component in a real container. Using htmlunit you can extract the output of the component from DOM and compare it with the expected output.

There is also another AbstractJsfTestCase in Shale-Test Framework, my main man Matthias has worked on it and added the JMock support to the library. My example uses the static mocks, to learn more about the jmock support in the framework, check out his cool example. Since converters and validators are interfaces they suit well to jmock. I’ve also used jmock to test the infrastructure(making managed beans aware of the jsf cycle) I’ve created and added to the project which I’m currently working for.

AbstractJsfTestCase reminds me the Abstract***SpringContextTests in Spring, the whole idea is speeding-up the web application development and gain time. I think any web framework should create it’s own TestCase in order to enable “Testing Without The Container”. Viva la AbstractJsfTestCase!

5 Responses to Testing JSF without the Container

  1. nice prefix of your tag.

  2. Derek says:

    I am trying to trap an event in a Junit test and locate a component on the mocked HTML page.

    This is my set up:
    // create the view
    UIForm parent = new HtmlForm();
    parent.setId(“form1”);

    // Add the components to the HTML Form
    button = new UICommand();
    button.setId(“button1”);
    button.setParent(parent);

    UIData table = new UIData();
    table.setId(“myTable”);
    table.setParent(parent);

    parent.setParent(facesContext.getViewRoot());

    In my test method I am doing the following:
    ActionEvent eventFC = new ActionEvent(button);
    UIComonent comp = eventFC.getComponent();
    comp.findComponent(“myTable);

    The second line is returning a null. Am I able to use these mock objects to find nested objects? Perhaps I am missing something?

    Thanks.

  3. Thanks Cagatay for that useful post.

  4. Shaik Rasool says:

    Sir,
    I have used this good article wrote by you can u tell me how to run the test cases writing in shale framework. And can u pls send the entire source code for this article so i can run and understand the process.

    Excepting a help full reply from your side..

  5. SARVESH NARAYAN says:

    Sir,

    I have been searching a standard Framework for long-2 time. I think, The quest might end here but i have not implemented due to lack of 100% understanding about SHALE framework. If u have any document/examples regarding this, plz suggest me. If possible, please suggest me any standard framework so that JSF+SPRING integration test can be done!!!

    Waiting for any excellent framework suggestion…thnx

%d bloggers like this: