Tuesday, September 2, 2008

Maven Integration Tests with Jetty and Selenium

in this post i'll describe how to configure maven to run integration tests with selenium and the maven-jetty-plugin. although this solution works, there surely are some points where it could be optimized (leave comments!). this solution assumes you have a maven-project configured for a web-application that can be run with the jetty plugin for maven. also, i assume that you have selenium/junit tests set up.

overview
this solution works in the following way:

  1. create two maven modules: one for the webapp, one for the integration tests

  2. install the war-file of the webapp to your maven repository

  3. in the integration test project set up the selenium/junit tests

  4. configure the surefire plugin to run the tests only in the integration-test phase

  5. use the maven-dependency plugin to download and unpack the war-file to the target directory of the integration-test project

  6. run the unpacked webapp with the jetty plugin

  7. start the selenium server with the selenium plugin

  8. run the integration tests



the details



set up the multi-module project

first of all, make your maven project a multi-module project in order to run the integration tests in a separate module apart from you ordinary junit tests. so you'll have three projects: a webapp-parent project, a webapp (war) project and a webapp-integration-tests (jar) project. for more information on setting up a multi-module project see the definitive guide to maven. here are excertps of the projects' poms:

webapp-parent pom.xml:

<project>
<modelVersion>4.0.0</modelVersion>
<groupId>de.foo.webapp</groupId>
<artifactId>webapp-parent</artifactId>
<packaging>pom</packaging>
<name>WebApp Parent</name>
<version>1.0</version>
<modules>
<module>../webapp</module>
<module>../webapp-integration-tests</module>
</modules>
...


webapp pom.xml. the webapp-integration-tests is like this but packaging is jar:

<project>
<modelVersion>4.0.0</modelVersion>
<groupId>de.foo.webapp</groupId>
<artifactId>webapp</artifactId>
<packaging>war</packaging>
<name>WebApp</name>
<parent>
<groupId>de.foo.webapp</groupId>
<artifactId>webapp-parent</artifactId>
<version>1.0</version>
</parent>
...


unpack the war file

in most cases the maven jetty plugin is used to run the the project it is configured for as a webapp. in this case we'll configure the jetty plugin in the integration-tests project to run the webapp project's generated war-file. to do so, the web app war has to be installed to your local repository (run mvn install). this war file can be fetched and unpacked in the integration-tests project with the maven dependency plugin:


<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>dependency-maven-plugin</artifactId>
<executions>
<execution>
<id>get war</id>
<phase>generate-resources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>de.foo.webapp</groupId>
<artifactId>webapp</artifactId>
<version>1.0</version>
<type>war</type>
</artifactItem>
</artifactItems>
<outputDirectory>${project.build.directory}/webapp/webapp</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
...


set up the jetty plugin

first, tell the jetty plugin to run the unpacked war-file by placing a jetty.xml file in the src/test/resources folder of the integration-tests project which defines the webapp directory. you can use the default jetty.xml and set the webAppDir parameter to point to the target directory:
<Set name="webAppDir">target/webapp</Set>
. then in the pom.xml configure the jetty plugin to run in the pre-integration-test phase.


<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<configuration>
<daemon>true</daemon>
<webApp>target</webApp>
<jettyConfig>target/test-classes/jetty.xml</jettyConfig>
</configuration>
<executions>
<execution>
<id>start jetty server</id>
<phase>pre-integration-test</phase>
<goals>
<goal>run-war</goal>
</goals>
</execution>
</executions>
</plugin>
...


you can try maven integration-test or maven jetty:run-war to see if this works as expected (set the daemon parameter to false before trying this).




set up the selenium plugin

the selenium plugin then starts a selenium server in the pre-integration-test phase, too. keep in mind that the configured maven goals run in the order they were defined in the pom.

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


set up the tests

next, move your integration tests to src/test/java in the integration-tests project. these can be run with the maven surefire plugin. this has to be configured to run the tests only in the integration-test phase.


<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests>
</configuration>
<executions>
<execution>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<skipTests>false</skipTests>
</configuration>
</execution>
</executions>
</plugin>


that's it. call maven integration-test to run the tests.

No comments: