Skip to content

Integration Tests with Selenium and tomcat7-maven-plugin

Integration tests are a valuable tool in the development of robust, quality software. Once each individual component has been unit tested, the integration test gives some confidence that the system stack as a whole does what is expected. Like unit tests, a great deal of the value of integration tests comes from the regression suite that they create. After any defect fix or enhancement to software, the unit and integration tests confirm that all existing features do exactly what they did before. If these tests are automated, they cost nothing to run and they’ll stay silent unless a defect is discovered.

I’ve looked at unit testing a few times in the past but this post explains how to integration test the full stack – database, Java application and web server. In this case, I’m running the tests as part of the Maven build lifecycle. As usual, I’m working from the Spanners demo (available for download), mainly working against the spanners-struts web component.

Launch Tomcat from Maven

To create an automated integration test of my spanners-struts webapp, I need a way of launching it as part of the Maven build process. In the past I’ve used the Maven Jetty Plugin but I’d prefer to launch my application in Tomcat as that’s the container I use in ‘production’. There are two ways I could do this. The first would be to install the Tomcat server on my build machine(s) and ensure that it’s running when I run a Maven build. I could configure Maven to deploy the built artifact (webapp war) to the local Tomcat and then run the tests against that (it’s also possible to deploy to a remote machine in the same way). I’d prefer not to do this as it makes my build less portable. I could only build on a machine that has access to a Tomcat server.

I prefer to actually spawn a new Tomcat instance from Maven using the tomcat7-maven-plugin. After Maven builds the artifact (webapp war) and immediately before it starts running Integration Tests (the pre-integration-test phase), Maven starts up its own instance of Tomcat and deploys the newly built war. After the tests are complete (on success or fail), Maven stops this instance of Tomcat. All of this can be done by configuring the plugin:

<plugin>
    <groupId>org.apache.tomcat.maven</groupId>
    <artifactId>tomcat7-maven-plugin</artifactId>
    <version>2.0</version>
    <configuration>
        <path>/spanners-struts</path>
        <contextFile>${basedir}/src/test/resources/tomcat/context.xml</contextFile>
        <useTestClasspath>true</useTestClasspath>
    </configuration>
    <executions>
        <!-- At pre-integration-test phase, run the war in an embedded Tomcat server. -->
        <execution>
            <id>start-tomcat</id>
            <phase>pre-integration-test</phase>
            <goals>
                <goal>run-war-only</goal>
            </goals>
            <configuration>
                <port>9090</port>
                <fork>true</fork>
            </configuration>
        </execution>
        <!-- At post-integration-test phase, stop the embedded Tomcat server. -->
        <execution>
            <id>stop-tomcat</id>
            <phase>post-integration-test</phase>
            <goals>
                <goal>shutdown</goal>
            </goals>
        </execution>
    </executions>
    <dependencies>
        <!-- Used to allow embedded Tomcat to connect to a MySQL database -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.21</version>
        </dependency>
    </dependencies>
</plugin>

 

The provided context.xml file is used to set up any resources required by Tomcat – in my case, just a connection to a local database (yes, I’m aware this goes against what I said earlier about making the build portable!)

<?xml version='1.0' encoding='utf-8'?>
<Context>

    <!-- Default set of monitored resources -->
    <WatchedResource>WEB-INF/web.xml</WatchedResource>

     <Resource name="jdbc/Spanners"
           auth="Container"
           type="javax.sql.DataSource"
           username="spanners"
           password="password"
           driverClassName="com.mysql.jdbc.Driver"
           description="spanners"
           url="jdbc:mysql://localhost:3306/spanners"
           maxActive="15"
           maxIdle="3"/>

</Context>

 

Note that I needed to add the mysql-connector-java dependency to the plugin. This effectively adds the MySQL driver jar to the Tomcat lib directory.

 Create some Selenium Tests

I created just a couple of very simple tests. Here’s the simplest. It just tests that the application has started and is accessible:

@Test
public void testAppStarted() {

    WebDriver driver = new HtmlUnitDriver();
    driver.get("http://localhost:9090/spanners-struts/");
    // Check that the login page is shown
    assertEquals("Login Page", driver.getTitle());
}

Now that we’ve got our first integration test written, we can easily expand our test suite to test login, page transitions, error handling and so on.

Run Maven

Now, on running various Maven goals, the embedded Tomcat server will start and the integration tests will run against it. This will happen when you invoke the Maven goal verify or any goal after (install, deploy etc.). With the build set up this way, it ensures that artifacts deployed to your repo have have the integration test suite run and pass.

PermGen space

Occasionally, Maven would throw the following error on attempting to run my application:

Error creating bean with name 'sessionFactory' defined in class path resource [spring-hibernate.xml]:
Invocation of init method failed;
nested exception is java.lang.OutOfMemoryError: PermGen space

I simply ignored this and increased the PermGen space available to Maven by setting the environment variable:

MAVEN_OPTS="-Xmx512m -XX:MaxPermSize=128m"
Published inHow ToTestingWeb Technologies

3 Comments

  1. Great, post. But I have an one question. Did not you add dependency or plugin for selenium ? How Selenium’s classes works? If so, what dependency or plugin did you add?
    thanks for sharing this post. Very good.

  2. Camilo: I did indeed add a dependency for Selenium to my Maven pom. Just the selenium-htmlunit-driver. This jar contains the HtmlUnitDriver which I used to run my tests.

    If you download the Spanners demo (link near the top of the post), take a look at the pom.xml in the spanners-struts module for an example of the required dependencies. Also, the SpannersStrutsIT.java is a simple example of a Selenium HtmlUnitDriver based test.

    Hope that helps!

Leave a Reply

Your email address will not be published. Required fields are marked *