Musings about this and that

September 25, 2007

JSF unit testing alternatives

Filed under: JSF, Unit Testing — ajesse @ 9:40 pm
Tags: ,

One of the advantages of JSF is that the application can be written free of references to JSF. All interfacing classes can be pure POJO’s. But if you try to test your own custom-components things get less easy.

OK, you can always test your components in a black-box testing approach. You write a test-webapplication using the component and verify that the rendered code is what you expected. Tools to support this are HtmlUnit, HttpUnit, Selenium, WebTest, and some others. (btw is there a comparision chart listing “all” of those web-app test frameworks?) But this kind of testing is cumbersome and error-prone. Some of the internals of a component cannot be tested at all or are very difficult to test.

What is really needed is some white-box testing framework for JSF. Some are available or should be available soon. So far I have found “Shale Test Framework”, “JSF-extensions test-time” and just recently “JSFUnit”. If you know of other JSF test frameworks, please let me know.

Shale Test Framework is the oldest one. Although it has a dependency on JSF 1.2 the website does not specify whether it provides support for testing JSF 1.2 components/applications.

JSF-Extensions is not so new, but so far no official release has been made. It supports JSF 1.2 and the “test-time” module provides mock objects for most or all JSF 1.2 classes. The source is easy to understand to make private extensions easy.

JSFUnit is the new-comer. They too have not yet done a release, they are too fresh off the press. At this moment you have to check out from svn and then build using maven. JSFUnit is based on Cactus. And I will give it a try in the next few days… stay tuned for more.

September 3, 2007

More Unit-testing with Selenium

Filed under: JSF, Selenium, Unit Testing — ajesse @ 8:20 pm

Some of my first Selenium unit-tests showed some strange behaviour: Every now and then a test would fail, even though a minute ago it worked and neither the test-code nor the webapp has been changed, I almost got the impression that it would be impossible to use Selenium for automated unit-testing of our framework: oo many releases would not be flagged as stable, because of erratically failed unit-tests.

Don’t know why, but at some point it dawned that maybe there was … a timing problem. Maybe some assertions were called before the result was delivered to the browser… and in the Selenium API I found methods like selenium.waitForPageToLoad(PAGE_LOAD_TIMEOUT) … isn’t that inspiring? Some tests and yes that was the solution. But use that method-call after each action? NO WAY

So time to write my SeleniumTestCase to be used as the base class and full of goodies (convenience methods):

import static org.junit.Assert.assertEquals;

import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.openqa.selenium.server.SeleniumServer;

import com.thoughtworks.selenium.DefaultSelenium;
import com.thoughtworks.selenium.Selenium;
import com.thoughtworks.selenium.SeleniumException;

public abstract class SeleniumTestCase {

  public static final String PAGE_LOAD_TIMEOUT = "10000";
  public static final String BASE_URL = "http://localhost:8080/myWebApp/";

  protected static Selenium seleniumStatic;
  protected Selenium selenium = null;

  public SeleniumTestCase() {
    this.selenium = seleniumStatic;
  }

  @BeforeClass
  public static void setUpBeforeClass() throws Exception {
    seleniumStatic = new DefaultSelenium("localhost", SeleniumServer.getDefaultPort(), "*firefox", BASE_URL);
    seleniumStatic.start();
  }

  @AfterClass
  public static void tearDownAfterClass() throws Exception {
    seleniumStatic.stop();
  }

  @Before
  public void setUp() throws Exception {
  }

  public boolean isAttributeMissing(String xPath){
    boolean result = true;
    try {
      selenium.getAttribute(xPath);
      result = false;
    } catch (SeleniumException e) {
      if (e.getMessage().contains("ERROR: Could not find element attribute: " + xPath)) {
        result = true;
      } else {
        throw(e);
      }
    }
    return result;
  }

  public boolean isElementMissing(String xPath){
    boolean result = true;
    try {
      selenium.getElementIndex(xPath);
      result = false;
    } catch (SeleniumException e) {
      if (e.getMessage().contains("ERROR: Element " + xPath + " not found")) {
        result = true;
      } else {
        throw(e);
      }
    }
    return result;
  }

  public Object getAttribute(String xPath){
    Object result = null;
    try {
      result = selenium.getAttribute(xPath);
    } catch (SeleniumException e) {
      if (e.getMessage().contains("ERROR: Could not find element attribute: " + xPath)) {
        result = null;
      } else {
        throw(e);
      }
    }
    return result;
  }

  public boolean submitAndWait(String formLocator) {
    boolean result = false;
    try {
      selenium.submit(formLocator);
      selenium.waitForPageToLoad(PAGE_LOAD_TIMEOUT);
      result = true;
    } catch (Throwable t) {
      result = false;
      System.err.println("--- received an exception: " + t);
    }

    return result;
  }

  public boolean clickAndWait(String elementLocator) {
    boolean result = false;
    try {
      selenium.click(elementLocator);
      selenium.waitForPageToLoad(PAGE_LOAD_TIMEOUT);
      result = true;
    } catch (Throwable t) {
      result = false;
      System.err.println("--- received an exception: " + t);
    }

    return result;
  }

  public boolean openAndWait(String url) {
    boolean result = false;
    try {
      selenium.open(url);
      selenium.waitForPageToLoad(PAGE_LOAD_TIMEOUT);
      result = true;
    } catch (Throwable t) {
      result = false;
      System.err.println("--- received an exception: " + t);
    }

    return result;
  }
}

With that base class, the tests can look like this:

selenium.type("id=containerForm:hideUser", "hide");
submitAndWait("id=containerForm");

… to be continued …

Blog at WordPress.com.