This answer provides a cookbook to install RestFixture and a section to present the Acceptance test framework.
Installation
One way to understand how to start with RestFixture is look at RestFixtureLiveDoc. The project provides the documentation for RestFixture itself and it is managed by Maven. Should you prefer going this way, please read below.
Assumptions
- you have a valid and working JDK installed (try from command prompt
java -version
)
- you have maven installed (try
mvn --version
)
- you have a version control software installed. Although, I won't discuss how to use it in the context of this answer.
Cookbook
Create an empty Maven project (as explained here). In a nutshell:
mvn archetype:generate -DgroupId=smartrics.restfixture.sample -DartifactId=scratch -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
- Change the names of the group and artifact accordingly, to suite you
- Remove the files
src/test/java/smartrics/restfixture/sample/*.java
src/main/java/smartrics/restfixture/sample/*.java
cd scratch
(or to whatever name you have chosen) and edit pom.xml
- Add the RestFixture dependency (the latest version of RestFixture is here). For example:
<dependency>
<groupId>smartrics.restfixture</groupId>
<artifactId>smartrics-RestFixture</artifactId>
<version>4.1</version>
</dependency>
- Add the Maven dependencies plugin to copy dependencies locally (this is not necessary but I find it convenient)
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<configuration>
<outputDirectory>${project.build.directory}/dependencies</outputDirectory>
</configuration>
<goals>
<goal>copy-dependencies</goal>
</goals>
</execution>
</executions>
</plugin>
- Right now, you should be able to
mvn package
and build/copy dependencies (check them in the target/dependencies
directory)
- You may want to update to the latest FitNesse version (Check the latest version available here), by adding
<dependency>
<groupId>org.fitnesse</groupId>
<artifactId>fitnesse</artifactId>
<version>20151230</version>
</dependency>
- Then do
mvn clean package
- Create a file
start.bat
with this content, to create a start command for fitnesse (On Linux you should be able to create an equivalent start.sh
):
setLocal EnableDelayedExpansion
set CLASSPATH="
for /R target\dependencies %%a in (*.jar) do (
set CLASSPATH=!CLASSPATH!;%%a
)
set CLASSPATH=!CLASSPATH!"
java -cp !CLASSPATH! fitnesseMain.FitNesseMain -p 9090 -d src\main\resources -e 0
- start FitNesse with the
start.bat
(it will take some time for FitNesse to create all the relevant resources)
- From your browser go to
http://localhost:9090
to check it works
- You can stop FitNesse with
CTRL-C
- You should at this point consider to commit to version control. If you use git, these items may be added to the ignore list:
target/
src/main/resources/FitNesseRoot/files/testResults
src/main/resources/FitNesseRoot/ErrorLogs
src/main/resources/FitNesseRoot/RecentChanges
src/main/resources/FitNesseRoot/properties
src/main/resources/FitNesseRoot/updateDoNotCopyOverList
src/main/resources/FitNesseRoot/updateList
src/main/resources/FitNesseRoot/Fitnesse/UserGuide
src/main/resources/FitNesseRoot/PageFooter
src/main/resources/FitNesseRoot/PageHeader
src/main/resources/FitNesseRoot/TemplateLibrary
With FitNesse running, got to the home page and edit.
- Add this wiki word
MyTestSamples
somewhere in the page, then save.
- You should see
MyTestSamples[?]
because the page doesn't exist.
- Click on the question mark to edit the page
- Append the following lines
!define TEST_SYSTEM {slim}
!path target/dependencies/*.jar
to add a reference to the RestFixture classes and dependencies and use the Slim Test system
- In the
MyTestSamples
page Add a new Test page from the Add menu.
- call the page
MySample1
, save
- Go to
MySample1
, edit the page and type the following content. Then save
| Import |
| smartrics.rest.fitnesse.fixture |
|Table: Rest Fixture | http://jsonplaceholder.typicode.com/ |
| GET |/users | 200 | Content-Type : application/json; charset=utf-8 | jsonbody.length == 10|
- If all went OK, by hitting Test on the page, the test should run and pass.
You could achieve the same setup by constructing the project by hand by downloading and unzipping the RestFixture with dependencies (download from the link bin.zip here). But I find the Maven approach simpler in the longer run.
Logging
RestFixture uses slf4j but doesn't come with logger bridge. To complete the configuration of the logging system add the following dependencies:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.20</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.20</version>
</dependency>
Then create the configuration file at src\main\resources\log4j.xml
with the following content
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
<appender name="FILE" class="org.apache.log4j.FileAppender">
<param name="file" value="restfixture.log" />
<param name="append" value="false" />
<param name="threshold" value="debug" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{ISO8601} %-5p [%c{1}] - %m%n" />
</layout>
</appender>
<category name="smartrics.rest.client" additivity="false">
<priority value="INFO" />
<appender-ref ref="FILE" />
</category>
<category name="smartrics.rest.fitnesse.fixture" additivity="false">
<priority value="DEBUG" />
<appender-ref ref="FILE" />
</category>
<category name="httpclient.wire" additivity="false">
<priority value="ERROR" />
<appender-ref ref="FILE" />
</category>
<root>
<priority value="ERROR" />
<appender-ref ref="FILE" />
</root>
</log4j:configuration>
The httpclient.wire
logger can be set to DEBUG to observe HTTP traffic on the wire.
For logging in the FitNesse server (outside the scope of this tutorial) check here
JUnit runner:
FitNesse tests can be run via JUnit as well, using the Maven Surefire plugin.
Create a test class runner in src/test/java/smartrics/restfixture/sample/RunnerTest.java
package smartrics.restfixture.sample;
import java.io.File;
import org.junit.Before;
import org.junit.Test;
import fitnesse.junit.JUnitHelper;
public class RunnerTest {
private JUnitHelper helper;
@Before
public void prepare() {
helper = new JUnitHelper("src/main/resources", new File("target", "fitnesse-junit").getAbsolutePath());
helper.setPort(9090);
}
@Test
public void restFixtureTests() throws Exception {
helper.assertSuitePasses("MyTestSamples.MySample1");
}
}
Then install the surefire plugin in the pom file:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.17</version>
<configuration>
<forkMode>always</forkMode>
</configuration>
</plugin>
Save the pom.xml file and run mvn clean package
to run the build with tests.
The build will pass and the report will be available in /target/fitnesse-junit/MyTestSamples.MySample1.html
References
- The pom.xml is here
- The start.bat is here
Acceptance tests
RestFixture has been designed to focus on the REST API exposed by the service under test. Mixing and matching Wiki content with structured fixtures does provide the best of both worlds for providing live documentation.
RestFixture can also be extended to provide additional functionality.
When writing acceptance tests focused on the API it's important highlight the parts of an HTTP request/response interaction: the VERB, the URI, the request/response BODY, the request/response HEADERs and the RETURN status code.
RestFixture does so by expressing each of these parts in a FitNesse table form:
| Table: Rest Fixture | <base uri> |
| setBody | <body> |
| setHeaders | <headers>
| VERB | /URI | <expected return status code> | <expected response headers | <expected response body> |
The <expected ...>
cells may be empty. If empty, no expectation will be checked.
setHeaders
and setBody
are only relevant for verbs requiring an entity (POST, PUT, ...)
Moreover, by using let
it's possible to extract data from parts of the HTTP response and share it with other fixtures and tests.
(RestFixtureLiveDoc)1 has a comprehensive set of examples for the various features implemented by RestFixture, but here follows - for reference - an extract of the main ones.
RestFixtureConfig
(RestFixtureConfig)11 is a simple fixture to set RestFixture configuration parameters. Config parameters can be overridden in named config fixtures and passed on to RestFixture instances. For example
|Table: Rest Fixture Config | my_config |
| name1 | value1 |
| name2 | value2 |
|Table: Rest Fixture | http://host:8080/path | my_config |
| ... |
RestFixture operations
The supported HTTP operations are: GET
, POST
, PUT
, DELETE
, HEAD
, OPTION
, TRACE
. For example:
| Table: Rest Fixture |http://host:8080 |
|GET | /resources/0 | 200 | Content-Type: application/json | jsonbody.name === 'Ted' |
OR
| Table: Rest Fixture |http://host:8080/path |
|GET | /resources/0 | 200 | Content-Type: application/xml | //name[text()='Ted'] |
Depending on the information that the author may want to convey expectation cells (3rd, 4th and 5th cell on each row) may be supplied for verification.
Simple fixtures like the examples above may be provided to test and document the service exposed REST api.
Sharing data
Data is shared using let
to extract from the response.
| Table: Rest Fixture |http://host:8080/path |
|GET | /resources/0 | 200 | Content-Type: application/json | jsonbody.name === 'Ted' |
| let | name | js | response.jsonbody.name | |
In here, the symbol name
is set to the value of the json expression response.jsonbody.name
. response
is a json object containing the last HTTP response, jsonbody
is an object in response containing the JSON object in the response body.
The symbol can be further used in other fixtures:
| setBody | { 'some_name' : '%name%' } |
or
| script | another fixture |
| check | not null | $name |
Transactions
The system can be also test and documented for multiple operations providing an application transaction (in a lose meaning here).
| Table: Rest Fixture | http://host:port |
| comment | an order is created ... |
| POST | /orders | | | |
| let | orderIdUri | header | Location: (.+) | |
| GET | %orderIdUri | | | |
| let | email | js | response.jsonbody.address.email |
| setBody |!- {
'payload' : {
'message' : 'order sent',
'email' : '%email%
}
-!|
| comment | and a confirmation can be sent |
| POST | /notifications | 201 | | |
The example above documents a way to use the API as an application transaction.
Extending RestFixture
RestFixture can be extended to provide additional functionality. Two methods are provided:
- Via Java: extend the RestFixture java to add/change the behaviour. For examples check the (RestFixtureExtensions)12 project.
- Via Javascript: As described below
Simple Javascript code can be embedded in RestFixture via configuration.
| Table: Rest Fixture Config | imp |
| restfixture.javascript.imports.map | !- sampleJs=src/main/resources/FitNesseRoot/files/javascript/sample.js -|
The config above - when used - will load the Javascript in the file provided as path and make it available in the context of the expectations handler:
| Table: Rest Fixture |http://host:port | imp |
| GET | /resources/1.json | 200 | | |
| let | sum | js | var sum = sampleAdd(1, 2); sum;| |