Executable specs are an important part of a test-driven project. I've used several tools such as FIT, Fitnesse, and GreenPepper to add executable specs that verify my project's functionality, but none of them really felt right to me. My biggest hangup had to do with using tables to express specifications when the thing I'm testing is not tabular in nature. Also, these tools are notoriously difficult (or even impossible) to run individually in my IDE like any of my other JUnit tests.
But then I found Concordion. Concordion is a FIT-like tool, created by David Peterson, for creating executable specifications. But unlike those other tools, Concordion is template-driven, not table-driven. And Concordion specs are more closely tied to JUnit such that they can be executed using the same mechanisms as any other JUnit test.
As a departure from my normal Spring-centric ramblings, today I'd like to show you how to setup Concordion for use in Eclipse and Maven 2-built projects. And I'll show you a very basic Concordion example that you can use as a starting point for adding Concordion to your projects.
There's actually very little setup required to setup Concordion--it mostly involves adding Concordion to your classpath. The very first thing you'll need to do is to manually install Concordion in your local Maven repository. That's because Concordion is not yet available in any public Maven repository (David tells me that it's on his to-do list, though). In case you're not familiar with Maven's "install:install-file" goal, here's what you'll need to do:
% mvn install:install-file -DgroupId=org.concordion -DartifactId=concordion
-Dversion=1.1.0 -Dpackaging=jar -Dfile=concordion-1.1.0.jar
Next, you'll need to add Concordion (and a couple of its dependecies) to your project's pom.xml:
<dependency> <groupId>org.concordion</groupId> <artifactId>concordion</artifactId> <version>1.1.0</version> <scope>test</scope> </dependency> <dependency> <groupId>xom</groupId> <artifactId>xom</artifactId> <version>1.1d2</version> <scope>test</scope> </dependency> <dependency> <groupId>ognl</groupId> <artifactId>ognl</artifactId> <version>2.7.2</version> <scope>test</scope> </dependency>
Since Concordion specs are primarily implemented as JUnit test cases, there's no need for any special Maven plugin. Maven's Surefire plugin, the plugin that runs all unit tests in a Maven build, will handle Concordion specs with no problem. The only thing you'll probably want to do is to tweak Surefire's configuration to make sure that Concordion writes its results to a directory under the "target" directory (by default Concordion writes results to "/tmp/concordion"). To do this, add the following to the <build>/<plugins> portion of your pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemProperties>
<property>
<name>concordion.output.dir</name>
<value>target/concordion</value>
</property>
</systemProperties>
</configuration>
</plugin>
Now you're ready to start writing specs. Like some other executable spec tools, Concordion specs are expressed in HTML. Unlike those other tools, however, Concordion specs are not necessarily table-driven. Instead, they are template-driven, as illustrated in the following basic specification (in a file named "CamelUtils.html"):
<html xmlns:concordion="http://www.concordion.org/2007/concordion">
<head>
<title>Spec: CamelUtils</title>
</head>
<body style="font-family:arial;">
<h2>CamelUtils</h2>
<p>CamelUtils is a simple utility class that supports manipulation of
camel-cased String values.</p>
<div>
<h3>Examples</h3>
<p concordion:execute="#result = createSentence(#input)">
When given a String containing
"<span concordion:set="#input">doSomethingReallyAwesome</span>",
CamelUtils.camelCaseToSentence() should return
"<span concordion:assertEquals="#result">Do something really awesome</span>".
</p>
</div>
</body>
</html>
This spec uses three of the attributes defined in the Concordion namespace. The concordion:execute attribute specifies a method to invoke on the fixture class (which we'll see in a moment). In this case, I want to invoke the createSentence() method, passing in whatever value is bound to the Concordion variable named "#input" and bind the results to a variable named "#result". Within the paragraph element, I use the concordion:set attribute to set the value of the "#input" variable to the String contained within the <span> tag. Then, I use the concordion:assertEquals attribute to assert that "#result" is equal to "Do something really awesome".
The nice thing about this template-driven approach is that it reads in plain English when viewed in a web browser.
Now let's look at the fixture class (CamelUtilsTest.java):
package com.habuma.camel;
import org.concordion.integration.junit4.ConcordionRunner;
import org.junit.runner.RunWith;
@RunWith(ConcordionRunner.class)
public class CamelUtilsTest
{
public String createSentence(String in)
{
CamelUtils camelUtils = new CamelUtils();
return camelUtils.camelCaseToSentence(in);
}
}
CamelUtilsTest is a JUnit 4-style test class. But unlike typical test classes, there are no test methods. Instead, it is annotated with @RunWith to indicate that Concordion will be responsible for executing this test and making all of the assertions. ConcordionRunner does this by looking for an HTML file with the same name as the test class (minus "Test", if the class is so named). So, when ConcordionRunner executes CamelUtilsTest, it will look for an HTML file named "CamelUtils.html" in the same package and use that HTML file as the spec.
The really beautiful thing about CamelUtilsTest is that it can be executed in Eclipse (or IntelliJ or NetBeans or whatever JUnit-aware IDE you choose) as if it were any other JUnit test case. And that's because it is just another test case. You'll get the same instant green-bar/red-bar feedback you'd get with any other JUnit test case.
Additionally, the results of the spec execution will be written to a copy of the HTML file. By default, Concordion output is written to a directory named "concordion" under whatever is deemed to be your system's "temp" folder. If you're on a Unix box, that's probably "/tmp/concordion". If the test passes, this is what you might see:
The green-highlighted area indicates the tested portion of the spec that passed. Conversely, a red-highlighted area indicates failure:
Chances are that you'd rather Concordion write its results to somewhere other than /tmp/concordion. If that's the case, you can configure the output directory by setting an environment variable named concordion.output.dir. The adjustments to Maven's Surefire plugin above handle this for your Maven builds. In Eclipse, this is easy to set globally for all of your projects by going into the "Preferences..." menu:
- Select Java->Installed JREs from the tree on the left.
- Select your JVM from the list on the right.
- Click "Edit..."
- Enter "-Dconcordion.output.dir=target/concordion" in the Default VM Arguments field.
From then on, Concordion output will be written to the target/concordion directory of whatever project your tests are in.
If you want a ready-to-run example of Concordion using Maven 2, you can download the examples from this article from here.

