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 …

August 23, 2007

Unit-testing JSF components with Selenium

Filed under: JSF, Selenium, Unit Testing — ajesse @ 9:51 am

After some tests with HtmlUnit I decided to give Selenium another try. Selenium has a nice interactive mode with the SeleniumIDE, but for our use, we need JUnit-based tests. JUnit and Selenium means that one has to use Selenium RC (RC= Remote Control).

With Selenium RC you start a Jetty-server that controls the browser that then accesses your web-application. With this cofiguration it is possible to use 3 different computers (1 to run the JUnit tests, 1 to host the SeleniumRC server and the browser and 1 to host the web-application), but the API’s for the Selenium-RC server expose the underlying Jetty-server. With this a minimal installation could host the web-applicaiton within the Selenium-RC server. The tutorial usually show how to start the Selenium-RC server from the command-line or from the Ant-scripts.

I prefer to start and stop the Selenium-RC server from Java-code. In order to maintain the maximum flexibility I created a simple class that controls the Selenium-RC server. This allows to start the server before the whole test-suite or (the other extreme) for each single test-method.

import org.openqa.selenium.server.SeleniumServer;
public class SeleniumServerControl {
  private static final SeleniumServerControl instance = new SeleniumServerControl();
  public static SeleniumServerControl getInstance() {
    return instance;
  }
  private SeleniumServer server = null;
  protected SeleniumServerControl() {
  }
  public void startSeleniumServer() {
    if (server == null) {
      try {
        server = new SeleniumServer(SeleniumServer.DEFAULT_PORT);
        System.out.println(" selenium server " + server.toString());
      } catch (Exception e) {
        System.err.println("Could not create Selenium Server because of: "
            + e.getMessage());
        e.printStackTrace();
      }
    }
    try {
      server.start();
    } catch (Exception e) {
      System.err.println("Could not start Selenium Server because of: "
          + e.getMessage());
      e.printStackTrace();
    }
  }
  public void stopSeleniumServer() {
    if (server != null) {
      try {
        server.stop();
        server = null;
      } catch (Exception e) {
        System.err.println("Could not stop Selenium Server because of: "
            + e.getMessage());
        e.printStackTrace();
      }
    }
  }
}

In its current form it starts the Selenium-RC server with its default-values and has only reduced error-handling. But for the moment it works.

In our setup we want to start the Selenium-RC server once for the complete test-suite. The JUnit-version is 4 which is more fexible using annotated testcasesand the setupBeforeClass-method, but seemingly has lost the test-suite that was available older JUnit versions. After some hours spent cruising the net I found this solution:

Basically it uses the old JUnit-testsuite feature to run the new testcases. The actual test-suite looks like this:

import org.junit.runner.RunWith;
import org.junit.runners.Suite;

@RunWith(Suite.class)

@Suite.SuiteClasses({
  TestHomePage.class
  , TestTabbedPane.class
})

public class TestSuite extends SeleniumTestSuite {
  // gotta get used to empty class-bodies...

}

And the referenced parent-class:

import org.junit.AfterClass;
import org.junit.BeforeClass;

import com.csg.jsftest.selenium.base.SeleniumServerControl;

public abstract class SeleniumTestSuite {

  @BeforeClass
  public static void setUpBeforeClass() throws Exception {
    SeleniumServerControl.getInstance().startSeleniumServer();
  }

  @AfterClass
  public static void tearDownAfterClass() throws Exception {
    SeleniumServerControl.getInstance().stopSeleniumServer();
  }

}

I still have to research whether it is a Java- or a JUnit-feature that executes the parent-classes static methods when instantiating the actual test-suite. Anyway thanks to this behaviour the actual test-suite setup can be done in the common parent-class. It’s also nice that the @BeforeClass and @AfterClass annotations are executed even though no actual @Test annotation is present.

Now its time to write the testcases … and maybe some helper-methods in a parent-class?

… to be continued …

August 22, 2007

Jazoon talk slides available

Filed under: JSF — ajesse @ 11:23 pm

The slides from the Jazoon conference are finally available from the official Jazoon website. You also find there the slides from my presentation “JSF in large companies“.

August 15, 2007

HtmlUnit

Filed under: JSF, Unit Testing — ajesse @ 4:34 pm

Inspired through the news about the new HtmlUnit version (TheServerSide-News) I decided to give it a try to test some JSF application. One of the first things were some error-messages about redirection, as described in this HtmlUnit-FAQ-entry. Well I could not accept that… and some intense minutes of digging into some sourcecode… here is a possibility to turn off those error-messages:

In the setUp()-method, or under Junit 4 the setUpBeforeClass()-method, I added these two lines:

System.getProperties().put(
   "org.apache.commons.logging.Log",
   "org.apache.commons.logging.impl.SimpleLog");
System.getProperties().put(
   "org.apache.commons.logging.simplelog.log.org.apache.commons.httpclient.HttpMethodDirector",
   "fatal");

And the error-messages are gone. The same things could be done in a config-file, but dealing here with unit-testing I prefer to do it directly in Java. The most difficult thing was determining the name of the second property.

more to follow…

August 2, 2007

JSF Usergroup CH Meeting #1 (slides)

Filed under: JSF, JSFDays — ajesse @ 1:24 pm

Ed Burns also has an entry on this meeting and in his blog you can find the links to the presentations.

July 12, 2007

JSF Usergroup CH Meeting #1

Filed under: JSF, JSFDays — ajesse @ 4:05 pm

Lovely is the black&white beauty in the center.A group of 18 people from Switzerland, Austria, Germany, America and Brazil met Thursday 29th June 2007 for a meeting to decide whether or not to found a JSF user group in Switzerland.

The interest in a JSF usergroup proves to be international.
Not only the international attendance, but also the feedback in the mailing lists and chat proves this.

First Ed Burns presented the possibilities of Scripting in the JSF context. The slides will be made available (when he comes back online). In a second presentation Ed showed us where the JSF spec’s will head.

To start the discussion on the foundation of the JSF Usergroup I showed some slides with ideas on this topic.

The discussion about the JSF Usergroup was intense and short. The decisions were taken very rapidly without objections:

  • Yes, we want a JSF usergroup
  • The best way is to organize as a Special Interest Group (SIG) under the umbrella of the Java Users Group Switzerland (JUGS)
  • For the organisational aspects 4 Swiss and 1 Brazilian declared their availability.
  • For presentations 4-5 Swiss and 3 “foreigners” volunteered.
  • A possible subject for a second meeting:
    • “Coming out”: members present their actual experiences in short presentations

The discussion very quickly drifted towards technical issues.

After 3 hours the group decided to award the status of “JSFDays Europe 2007″ to the meeting and the mandatory photos were taken (with the participation of “Lovely” the famous black and white cow). You can find the pictures in my photo gallery.

July 4, 2007

Starting

Filed under: miscellaneous — ajesse @ 10:52 pm

Signing up is easy, setting up requires some work, blogging will take time to get used to.

Yours sincerely

Alexander Jesse

« Previous Page

Blog at WordPress.com.