FitNesse and dependency management with Maven

Arjan Molenaar

As a software developer you're using dependency management to handle dependencies on your project; include frameworks and libraries to your project. If you're a Java developer you're probably using Maven. When you're not using Maven you're probably using one of the more versatile build tools like Ant or Gradle, both can use Ivy for dependency management. Either way, you're not putting binaries (jars) in your source control repository.

How about your FitNesse acceptance suite? Since it's all software and all belongs to the project, you probably want to have the same standards when executing the acceptance test suite. It's really not that different from executing your regular (unit) tests.

In this blog I'll explain how to launch a FitNesse suite from Maven. I'll also elaborate on how to get FitNesse to recognize the dependencies required to launch the application. A future post will be dedicated to the FitNesse/Ivy combo.

Launching FitNesse from Maven

When you start integration FitNesse through Maven, there are a few challenges ahead:

  1. Maven has a limited set of scopes in which you can define dependencies (compile, test, runtime)
  2. Maven is using a fixes set of execution phases.
  3. I'd like to start FitNesse in 2 modes: interactive and non-interactive.

Since FitNesse is about acceptance tests it makes sense to execute those in the integration-test phase. The integration-test phase is executed after the package stage. In interactive mode I'm not interested in a package, so I'll launch FitNesse from the test stage directly. The way to make this possible is by using profiles.

FitNesse in interactive mode

First things first: in order to do anything with FitNesse we need to include the dependency. To start FitNesse we'll use the runtime scope:

<dependencies>
  <!-- project dependencies go here ... -->
  <dependency>
    <groupId>org.fitnesse</groupId>
    <artifactId>fitnesse</artifactId>
    <version>20121220</version>
    <scope>runtime</scope>
  </dependency>
</dependencies>

This goes in the normal dependency section.

Now let's look at the profile. As said before, for interactive editing I'd like to start FitNesse from the test phase.

<profiles>
  <profile>
    <id>fitnesse</id>
    <build>
      <plugins>
        <plugin>
          <artifactId>maven-antrun-plugin</artifactId>
          <version>1.6</version>
          <executions>
            <execution>
              <id>start-fitnesse</id>
              <phase>test</phase>
              <configuration>
                <tasks>
                  <echo taskname="fitnesse" message="Starting FitNesse..." />
                  <java classname="fitnesseMain.FitNesseMain" classpathref="maven.runtime.classpath" fork="true">
                    <arg line="-p 8000" />
                    <arg line="-d ." />
                  </java>
                </tasks>
              </configuration>
              <goals>
                <goal>run</goal>
              </goals>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </build>
  </profile>
</profiles>

Mind the classpathref attribute on the Java tag. It's referencing the runtime classpath definition from Maven. That easy.

This will allow you to start FitNesse using the following command:

$ mvn -Pfitnesse test

Quite okay, right? You can start the wiki in stand-alone mode and use it as, well, a wiki.

Maven support in FitNesse

Now let's see if we can make FitNesse import some dependencies through Maven. The dependencies are stated in the pom.xml file, so it makes no sense duplicating those. Since dependencies change over time it's quite labour intensive to manage them by hand it FitNesse. The way to go is to include the maven-classpath-plugin. This plugin needs to be loaded along with the FitNesse binary, so FitNesse can make use of it. Let's include it in the profile, then the profile definition looks like this:

<profiles>
  <profile>
    <id>fitnesse</id>
    <build>
      <plugins>
        <plugin>
          <artifactId>maven-antrun-plugin</artifactId>
          <version>1.6</version>
          <executions>
            <execution>
              <id>start-fitnesse</id>
              <phase>test</phase>
              <configuration>
                <tasks>
                  <echo taskname="fitnesse" message="Starting FitNesse..." />
                  <java classname="fitnesseMain.FitNesseMain" classpathref="maven.runtime.classpath" fork="true">
                    <arg line="-p 8000" />
                    <arg line="-d ." />
                  </java>
                </tasks>
              </configuration>
              <goals>
                <goal>run</goal>
              </goals>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </build>
    <dependencies>
      <dependency>
        <groupId>org.fitnesse.plugins</groupId>
        <artifactId>maven-classpath-plugin</artifactId>
        <version>1.6</version>
        <scope>runtime</scope>
      </dependency>
    </dependencies>
  </profile>
</profiles>

That's it for the dependency. Now let's tell FitNesse about it. In a file named plugins.properties (in the same directory where your POM is located) we can define the plugin:

# plugins.properties: Configuration for FitNesse
SymbolTypes = fitnesse.wikitext.widgets.MavenClasspathSymbolType

We'll define our dependencies from a wiki page, hence define the plugin as SymbolType.

Now let's relaunch FitNesse (Ctrl-C to terminate the running instance). It gives a message saying the plugin is loaded:

 [fitnesse] Starting FitNesse 20121220... (Selenium 2.29.1)
      FitNesse (v20121220) Started...
          port:              8000
          root page:         fitnesse.wiki.FileSystemPage at ./FitNesseRoot
          logger:            none
          authenticator:     fitnesse.authentication.PromiscuousAuthenticator
          page factory:      fitnesse.responders.PageFactory
          page theme:        bootstrap
          page version expiration set to 0 days.
          Custom symbol types loaded:
              fitnesse.wikitext.widgets.MavenClasspathSymbolType

All that has to be done now is including the Maven classpath in hierarchy of the test suite. In a wiki page, define:

!pomFile pom.xml

If you save the file you should see a lot of "classpath" entries show up on the page.

By default it will load the test scope (this is not related to the fact that we started FitNesse from the test phase). The plugin will display all dependencies.

One remark: why did I add the FitNesse dependency to the project dependencies and the plugin to the profile dependencies? You'll need the fitnesse jar once you start executing tests. The plugin is not able to enable profiles at this moment. In practice this is hardly a problem.

Running integration tests

Executing FitNesse as part of the build cycle basically follows the same scheme. Let's put it in a profile that's active by default. This adds some flexibility in that the profile can be disabled to prevent the tests from running (for a local build or something).

<profiles>
  <!-- fitnesse profile omitted for clearity -->
  <profile>
    <id>fitnesse-integration</id>
    <activation>
      <activeByDefault>true</activeByDefault>
    </activation>
    <build>
      <plugins>
        <plugin>
          <artifactId>maven-antrun-plugin</artifactId>
          <version>1.6</version>
          <executions>
            <execution>
              <id>start-fitnesse-integration</id>
              <phase>integration-test</phase>
              <configuration>
                <tasks>
                  <echo taskname="fitnesse" message="Starting FitNesse..." />
                  <java classname="fitnesseMain.FitNesseMain" classpathref="maven.runtime.classpath" fork="true" failonerror="true">
                    <arg line="-p 8001" />
                    <arg line="-c FitNesse.SuiteAcceptanceTests?suite&amp;amp;format=text" />
                    <arg line="-d ." />
                  </java>
                </tasks>
              </configuration>
              <goals>
                <goal>run</goal>
              </goals>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </build>
    <dependencies>
      <dependency>
        <groupId>org.fitnesse.plugins</groupId>
        <artifactId>maven-classpath-plugin</artifactId>
        <version>1.6</version>
        <scope>runtime</scope>
      </dependency>
    </dependencies>
  </profile>
</profiles>

Where I put FitNesse.SuiteAccceptanceTests it should point to your acceptance suite. The -c option is used to execute a command from the command line. The commands have the same format as the URL would have when you execute it in interactive mode. Hence the ?suite&format=text.

Now the integration tests are executed autoamtically when you perform a mvn install.

Note: if your application is a webapp, you can choose to launch it in the pre-integration-test phase and shut it down in the post-integration-test phase. The de-facto web server to use is Jetty, but that's out of the scope of this blog. In the Xebium project, you can find a complete example of a POM file.

Dealing with Maven Home

By default Maven will look in $HOME/.m2/ for its settings.xml. When you have your settings on a different location you need to have the M2_HOME environment variable set to that location. The Maven classpath plugin takes into account the M2_HOME variable as of version 1.6.

Comments (7)

  1. Stewart - Reply

    March 4, 2013 at 8:20 pm

    This method of using Maven to bootstrap FitNesse worked very well for me, until I hit a very frustrating situation: the dependencies required by FitNesse itself (and Xebia) were not the same as (and in fact clashed with) dependencies required by the webapp under test, which was a Spring MVC webapp, running under Tomcat or Jetty.
    One solution is to the then create a completely separate Maven project for your FitNesse tests, and have them depend upon your webapp project. But this introduces other Maven complexities.
    The solution I came up with is a Maven plugin I called "FitNesse Launcher" which lets you run FitNesse both in "wiki mode" and as automated tests during Maven's integration-test phase.
    Take a look. Please let me know what you think. 🙂
    https://code.google.com/p/fitnesse-launcher-maven-plugin/

  2. RR - Reply

    September 17, 2013 at 5:43 pm

    If I need to run fitness test cases which are hosted on a different server . How do I integrate this from my maven build while running integration test.Please assist.

  3. SBL - Reply

    October 22, 2015 at 4:29 pm

    Thank you for this - I was able to start Fitnesse but when I add the !pomFile pom.xml in a file it throws an error: Please see below. Any ideas?

    WARNING: Unable to handle request [Invocation of method 'render' in
    class fitnesse.responders.WikiPageResponder$WikiPageRenderer threw exception ja
    va.lang.AbstractMethodError at wikiPage.vm[line 1, column 10]]

    • Arjan Molenaar - Reply

      October 26, 2015 at 11:13 am

      Hi, which version of FitNesse and which version of the Maven plugin are you using?

      • Colin - Reply

        February 9, 2016 at 11:12 pm

        I found from version Fitnesse version 20150114 Xebium no longer worked and threw the above mentioned error.

        For me I found I had to update the fitness plugin maven-classpath-plugin version to the latest version of 1.9.

        The issue was wtih !pomFile pom.xml, once I set that it crashed the web page.

  4. Haroon - Reply

    February 25, 2016 at 10:16 pm

    Hi, Is it possible to run this using maven exec plugin?

Add a Comment