Skip to main content

A quick primer on testing Selenium in Groovy

Posted by johnsmart on May 28, 2009 at 5:09 PM PDT

Selenium is a widely-used and very useful tool for automated web testing. This article is a very short primer designed to get you up and running Selenium Tests in Groovy in your Maven projects.

The examples assume you are running your Selenium tests against an existing web server (say an integration or staging server). In this case, I typically set up a dedicated Maven project to do the job. This project will start up a Selenium client, run some Selenium integration tests, and then shut down the Selenium client. An alternative approach is to start your application up in Jetty, which works fine as well, but involves a bit more configuration in the pom.xml file.

The test cases are written in Groovy, primarily because it is a real pleasure to write anything in Groovy :-). Easyb is also an excellent alternative that works well with Selenium. The Groovy tests by default go in the test/src/groovy directory. You can set up Groovy in your Maven project by adding the gmaven plugin, as shown here:


<plugin>
  <groupId>org.codehaus.groovy.maven</groupId>
  <artifactId>gmaven-plugin</artifactId>
  <version>1.0-rc-4</version>
  <executions>
    <execution>
      <goals>
        <goal>generateStubs</goal>
        <goal>compile</goal>
        <goal>generateTestStubs</goal>
        <goal>testCompile</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Next, you need to set up Selenium in your Maven project. You can use the Selenium plugin for this:


<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>selenium-maven-plugin</artifactId>
  <version>1.0-rc-1</version>
  <executions>
    <execution>
      <id>xvfb</id>
      <phase>pre-integration-test</phase>
      <goals>
        <goal>xvfb</goal>
      </goals>
    </execution>
    <execution>
      <id>start</id>
      <phase>pre-integration-test</phase>
      <goals>
        <goal>start-server</goal>
      </goals>
      <configuration>
        <background>true</background>
        <logOutput>true</logOutput>
      </configuration>
    </execution>
    <execution>
      <id>stop</id>
      <phase>post-integration-test</phase>
      <goals>
        <goal>stop-server</goal>
      </goals>
    </execution>
  </executions>
</plugin>>

Note that we have set up the Selenium client to start just before the integration tests, and to close down once the integration tests are finished. We also need to configure the Surefire plugin to run the Selenium tests during the integration-test phase. You can use whatever convention you want - in this case, the Selenium tests all go in a package called 'selenium', placed somewhere in the project class structure. In the following configuration, we ensure that these tests are only run during the integration-test phase:


<plugin>
  <artifactId>maven-surefire-plugin</artifactId>
  <configuration>
    <excludes>
      <exclude>**/*IntegrationTest.*</exclude>
      <exclude>**/selenium/**</exclude>
    </excludes>
    <forkMode>never</forkMode>
  </configuration>
  <executions>
    <execution>
      <id>integration-tests</id>
      <phase>integration-test</phase>
      <goals>
        <goal>test</goal>
      </goals>
      <configuration>
        <excludes>
          <exclude>**/*Base.java</exclude>
          <exclude>**/*$*</exclude>
        </excludes>
        <includes>
          <include>**/*IntegrationTest.*</include>
          <include>**/selenium/**</include>
        </includes>
      </configuration>
    </execution>
  </executions>
</plugin>

To make things a bit more flexible, we will be passing in the target URLs to the tests from the command line or via a Maven profile. Now, due to a bug/quirk in the current Maven surefire plugin, you need to set the forkMode option to never for this to work properly.

We will also need a dependency on the Selenium Java client classes for our test code later on:


<dependencies>
    <dependency>
      <groupId>org.seleniumhq.selenium.client-drivers</groupId>
      <artifactId>selenium-java-client-driver</artifactId>
      <version>1.0-beta-2</version>
      <scope>test</scope>
    </dependency>
</dependencies>

The Groovy classes themselves are fairly simple. We start off with a base class, which will set up the Selenium client, and shut it down cleanly after the tests. We use a property called base.url to ensure that we can run the tests against different servers as required:


public class SeleniumTestBase {

    /**
     * Only create one instance of this server for all the tests.
     */
    private static Selenium seleniumInstance

    /**
     * Base URL defined by the ${base.url} property.
     * Child classes should use this variable to ensure that tests are run
     * against the right test server.
     */
    private static String baseUrl;

    protected static synchronized Selenium getSelenium() {
        
        if (!seleniumInstance) {
            seleniumInstance = new DefaultSelenium("localhost", 4444,
                                                   "*firefox", getBaseUrl())
            seleniumInstance.start()
        }
        return seleniumInstance
    }

    public static String getBaseUrl() {
        if (!baseUrl) {
            baseUrl = System.getProperty("base.url") ?: ""
        }
        return baseUrl
    }

    @AfterClass
    public static synchronized void shutdown() { 
    	seleniumInstance.close()
    	seleniumInstance = null
    }    
}

Finally, the tests themselves are derived from this class, and use the selenium and baseUrl


public class VersionNumberTest extends SeleniumTestBase {

    @Test
    void homePageShouldHaveAVersionNumberInFooter() {
    	selenium.with {
            open "${baseUrl}/index.html"
            waitForPageToLoad "5000"
            assert isTextPresent(/regexp:myapp version \d+\.\d+\.\d+/)
    	}

    }
    ...
}

That should be enough to get you started with Selenium tests written in Groovy for your Maven projects - have fun!


"Probably the best training course I've been on."..."Not just how to write Java code but the 'business end' - how to build, test, deploy, manage and monitor"..."One of the best and most useful courses I have attended. And they didn't even try to sell me anything!" - Coming soon to London, Wellington, Auckland, Canberra and Sydney - Get up to speed with the latest and coolest in Java tools and best practices! Sign up on the 2009 season of the Java Power Tools Bootcamps.

Comments

I realise I'll probably get flamed for this, but selenium really is not a great tool. I've seen so many hours wasted maintaining scripts because it's so fragile. Worse than that, because of it's javascript injection, I've witnessed testers convincing developers to make a site less secure just so they can run selenium tests on it. If you're doing a project at home and can't afford a tool it's ok, because your time is your own. As far as a business tool goes, it's TCO is way too high due to frequent test script maintenance and introduced risks. Just because it's free, doesn't mean it's worth it. ROI goes backwards as TCO goes up. That said, nice work making it do what you wanted. Can I ask how long it took you to research and develop this work around? I too do projects at home. :)

That's cool, Selenium is not a fix-all solution. I usually use it from Java, using a BDD-like approach, rather than by recording scripts, though there are plenty of folk who do that too. Regarding TCO, in my experience ANY record-replay based testing tool will incure a pretty high maintenance overhead, even the (very) pricy commercial offerings. HTMLUnit is another promising option if you don't like running things in a browser or using javascript.