Musings about this and that

March 14, 2008

JSF Days 08 – almost over

Filed under: JSF, JSFDays, JSFUnit, Selenium, Unit Testing — ajesse @ 3:44 pm

To all those that forgot to come to Vienna: You definitely missed something really great.

3 days with many important people in the JSF ecospace (Kito: good definition of that) in a very relaxed context. Irian did a great job to organize this second JSFDays in a perfect way, which definitely helps to create this friendly mood.

For those not yet used to be able to get in “touch” with the great names of JSF were pleasently surprised how easy those persons behind the names are. This feature is definitely something I like in the JSF ecosphere. Despite being a difficult environment (todays webapp-development,…) JSF brings along a bunch of nice guys that are very approachable and helpfull. A great community. And this you can really feel here in Vienna at the JSFDays.

Almost a pity those 3 days are almost over… It will be a long time till JSFDays 2009.

The presentations will be available through Irian’s website. As soon as this happens I will report back.


I did a presentation on Testing JSF applications and components. Although one of my laptops started to misbehave… it went quite well. I got some nice feedback, questions and hints and wait impatiently for the official feedback analysis.I concentrated on Selenium and JSFUnit.The preparation for this talk are also the reason for the long time since my last post… but it also gave me some input for further posts ;)

November 12, 2007

Simple walkthrough testcase using SeleniumTestCase

Filed under: JSF, Selenium, Unit Testing, UnitTest — ajesse @ 7:17 pm

After all the preparations its time to write some tests. Imagine a sample-application that contains a page per component from a component set. For our nightly build we want to know whether all pages work. So a first test would be to use the browser and click through all pages. Annoying and always the same. Calls for an automated test, doesn’t it?

@Test public void checkCatalog() {
  openAndWaitWebAppRoot();
  clickAndWait("link=CATALOG");
  assertPageTitleEquals("JSF Components Catalog");
  clickAndWait("link=CATALOG");
  clickAndWait("link=Layout components");
  assertPageTitleEquals("Layout components");
  clickAndWait("link=Layout");
  assertPageTitleEquals("Layout Component");
  clickAndWait("link=Container");
  assertPageTitleEquals("Container Configurator");
  clickAndWait("link=GroupBox");
  assertPageTitleEquals("GroupBox Component");
  clickAndWait("link=Tabbed Pane");
  assertPageTitleEquals("TabbedPane Component");
  clickAndWait("link=MessageArea");
  assertPageTitleEquals("MessagesArea Component");
};

Looks easy, doesn’t it? Looks and feels just like the instructions for a human tester. And that’s the writing test should be: simple.

Such a test can also survive a revamp of the menu-structure of the application, as long as the texts of the menu-items remain constant, the testcase, just like the human tester, still find the links to click on. Was very usefull when we did such a refactoring of the sample-application. Every now and then someone from teh team would do the “cvs update”-redeploy-”let the testuite run”-cycle and just report which areas needed some massaging.

New tricks for SeleniumControl and SeleniumTestCase

Filed under: JSF, Selenium, Unit Testing, UnitTest — ajesse @ 6:47 pm

Since the original post introducing SeleniumControl and SeleniumTestCase these two classes learned some more tricks.

The most annoying thing I noticed about that code was, that I had to trigger the SeleniumTestSuite to be able to run a testcase. So I added a simple method to SeleniumControl (isStarted() returning true if server != null) to allow a testcase to query for that and, in case of need, to start the SeleniumServer on its own. The TestCase class checks for this in its setupBeforeClass()-method…

Now I can start either a SeleniumTestSuite, which results in the server started only once for the whole testsuite, or a SeleniumTestCase, which starts the server just for that single testcase. At the beginning the restriction did not hurt, only with the evolution of the test-suite (about 125 tests so far…) this started to itch.

After a few testcases I also added a method to SeleniumTestCase to open the web-applications root:

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

return result;
}

public String getWebAppRoot() {
return testHost + testAppl;
}

November 6, 2007

Preparing your JSF webapp for testing

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

Be it load&performance testing, be it unit-testing, it seems that all related tools have some problems with JSF’s dynamic ID-attributes.

With dynamic ID I want to indicate that the ID of a certain input-field or a button/link can change if

  • no fixed id is specified (id=…)
  • the page-structure changes (eg. conditionally rendered components in templates)
  • real page-changes (new requirements, refactorings)

I would say a testable JSF web-application has fixed ID’s for all input- and command-components. Pure output-components like h:outputText do not need a fixed ID.

So far this is the most important testability-criteria. Of course most things can be done otherwise. But it sure is more hassle. The load&performance test-tools are more dependent on the ID-attribute because it determines also the NAME-attribute. I consider the better testability more important than the minimal time-saving by not specifying the ID-attribute.

Selenium Toolkit (preparing to write Selenium Tests)

Filed under: Selenium, Unit Testing, UnitTest — ajesse @ 7:28 pm

What should you prepare when you want to write Selenium Tests in the form of Java JUnit tests?

I found that a few tools and urls can help to save your hair from getting too white:

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 …

Blog at WordPress.com.