Thomas Sundberg

November 1, 2012

A RESTFul Web Service

This post has been migrated to

Previous – A Swing application

A RESTFul web service is yet another way to use the model. It doesn’t have any user interface and it is expected to be used by third party suppliers. I divide the project using two Maven modules as earlier. One for the production code and one for the verification. The only large difference here is the support class that will connect to the system under test but now has to be adapted for a RESTFul web service instead of any graphical interface. Another difference is of course that there is no GUI and that it is developed using a Jersey servlet instead, but that has little impact on the verification.

The feature is the same:


Feature: Rental cars should be possible to rent to gain revenue to the rental company. As an owner of a car rental company I want to make cars available for renting So I can make money Scenario: Find and rent a car Given there are 18 cars available for rental When I rent one Then there will only be 17 cars available for rental

The glue to connect the feature above with Cucumber is the same as earlier:


package se.waymark.rentit; import cucumber.api.junit.Cucumber; import org.junit.runner.RunWith; @RunWith(Cucumber.class) public class RunCukesIT { }

The steps are identical:


package se.waymark.rentit.steps; import; import; import; import static; import static org.junit.Assert.assertThat; public class RentStepdefs { private RentACarSupport rentACarSupport = new RentACarSupport(); @Given("^there are (\\d+) cars available for rental$") public void there_are_cars_available_for_rental(int availableCars) throws Throwable { rentACarSupport.createCars(availableCars); } @When("^I rent one$") public void rent_one_car() throws Throwable { rentACarSupport.rentACar(); } @Then("^there will only be (\\d+) cars available for rental$") public void there_will_be_less_cars_available_for_rental(int expectedAvailableCars) throws Throwable { int actualAvailableCars = rentACarSupport.getAvailableNumberOfCars(); assertThat(actualAvailableCars, is(expectedAvailableCars)); } }

The first interesting difference is in the help class. It now deals with REST using RESTAssured rather than a web or Swing application.


package se.waymark.rentit.steps; import com.jayway.restassured.RestAssured; import com.jayway.restassured.response.Response; import com.jayway.restassured.response.ResponseBody; import static com.jayway.restassured.RestAssured.expect; public class RentACarSupport { public RentACarSupport() { RestAssured.baseURI = "http://localhost"; RestAssured.port = 8080; RestAssured.basePath = "/rentit/rest"; } public void createCars(int availableCars) { String path = "/create/" + availableCars; expect().statusCode(201).when().post(path); } public void rentACar() { String path = "/rent"; expect().statusCode(200).when().post(path); } public int getAvailableNumberOfCars() { String path = "/availableCars"; Response response = expect().statusCode(200).when().get(path); ResponseBody body = response.getBody(); String availableCarsAsString = body.asString(); return Integer.parseInt(availableCarsAsString); } }

Instead of using Selenium or FEST, I now use RESTAssured for driving the application.

This was the interesting part from a testing point of view.

To execute this, we need a Maven pom that defines the project


<?xml version="1.0" encoding="UTF-8"?> <project> <modelVersion>4.0.0</modelVersion> <parent> <groupId>se.waymark</groupId> <artifactId>rest-ws</artifactId> <version>1.0-SNAPSHOT</version> </parent> <groupId>se.waymark</groupId> <artifactId>rest-test</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <version>2.12</version> <executions> <execution> <id>integration-test</id> <phase>integration-test</phase> <goals> <goal>integration-test</goal> </goals> </execution> <execution> <id>verify</id> <phase>verify</phase> <goals> <goal>verify</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.codehaus.cargo</groupId> <artifactId>cargo-maven2-plugin</artifactId> <version>1.2.2</version> <executions> <execution> <id>start-tomcat</id> <phase>pre-integration-test</phase> <goals> <goal>start</goal> </goals> </execution> <execution> <id>stop-tomcat</id> <phase>post-integration-test</phase> <goals> <goal>stop</goal> </goals> </execution> </executions> <configuration> <container> <containerId>tomcat7x</containerId> <zipUrlInstaller> <url></url> </zipUrlInstaller> <output>${}/tomcat-logs/container.log</output> <append>false</append> <log>${}/tomcat-logs/cargo.log</log> </container> <configuration> <type>standalone</type> <home>${}/tomcat-home</home> <properties> <cargo.servlet.port>8080</cargo.servlet.port> <cargo.logging>high</cargo.logging> </properties> <deployables> <deployable> <groupId>se.waymark</groupId> <artifactId>rest-main</artifactId> <type>war</type> </deployable> </deployables> </configuration> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>se.waymark</groupId> <artifactId>rest-main</artifactId> <version>1.0-SNAPSHOT</version> <type>war</type> <scope>test</scope> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-server</artifactId> <version>1.13</version> <scope>test</scope> </dependency> <dependency> <groupId>com.jayway.restassured</groupId> <artifactId>rest-assured</artifactId> <version>1.6.2</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> <scope>test</scope> </dependency> <dependency> <groupId>info.cukes</groupId> <artifactId>cucumber-java</artifactId> <version>1.1.1</version> <scope>test</scope> </dependency> <dependency> <groupId>info.cukes</groupId> <artifactId>cucumber-junit</artifactId> <version>1.1.1</version> <scope>test</scope> </dependency> </dependencies> </project>

It is similar to the web application versions. It uses Maven fail-safe plugin to execute the test and cargo to deploy the application on a Tomcat.

The RESTFul web service

To be able to build the system, I need to implement the RESTFul web service. This is a trivial RESTFul web service and not really important but included here for completeness. I will therefore skip through it fast. All files needed are included, but I will not go through the details. There are a lot of other people out there who are better sent to describe a RESTFul web service than I am.

File organisation

All files needed for this example are organised like this:

|-- pom.xml
|-- rest-main
|   |-- pom.xml
|   `-- src
|       |-- main
|       |   |-- java
|       |   |   `-- se
|       |   |       `-- waymark
|       |   |           `-- rentit
|       |   |               `-- rest
|       |   |                   `--
|       |   `-- webapp
|       |       `-- WEB-INF
|       |           `-- web.xml
|       `-- test
|           `-- java
|               `-- se
|                   `-- waymark
|                       `-- rentit
|                           `--
`-- rest-test
    |-- pom.xml
    `-- src
        `-- test
            |-- java
            |   `-- se
            |       `-- waymark
            |           `-- rentit
            |               |--
            |               `-- steps
            |                   |--
            |                   `--
            `-- resources
                `-- se
                    `-- waymark
                        `-- rentit
                            `-- Rent.feature

All test files has already been presented so I will not do that again. The files needed for the RESTFul web service looks like this:

Parent pom

A parent pom is used to connect the two sub modules. It is defined as:


<?xml version="1.0" encoding="UTF-8"?> <project> <modelVersion>4.0.0</modelVersion> <groupId>se.waymark</groupId> <artifactId>rest-ws</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> <modules> <module>rest-main</module> <module>rest-test</module> </modules> </project>

Main application pom


<project xmlns="" xmlns:xsi="" xsi:schemaLocation=""> <modelVersion>4.0.0</modelVersion> <parent> <groupId>se.waymark</groupId> <artifactId>rest-ws</artifactId> <version>1.0-SNAPSHOT</version> </parent> <groupId>se.waymark</groupId> <artifactId>rest-main</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <build> <finalName>rentit</finalName> </build> <dependencies> <dependency> <groupId>se.waymark.educational</groupId> <artifactId>model</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-server</artifactId> <version>1.9</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> <scope>test</scope> </dependency> </dependencies> </project>

Nothing interesting here. It builds a web application and gives it the final name rentit.

The web service

The web service is implemented as:


package; import se.waymark.rentit.model.dao.CarDAO; import se.waymark.rentit.model.dao.InMemoryCarDAO; import se.waymark.rentit.model.entiy.Car; import; import; import; import; import; @Path("/") public class RentCar { private static CarDAO carDAO = new InMemoryCarDAO(); @POST @Path("/create/{param}") public Response createCars(@PathParam("param") Integer numberOfCars) { for (int i = 0; i < numberOfCars; i++) { Car car = new Car(); carDAO.add(car); } return Response.status(201).build(); } @POST @Path("/rent") public Response rentCar() { Car car = carDAO.findAvailableCar();; return Response.status(200).build(); } @GET @Path("/availableCars") public Response getAvailableCars() { int availableCars = carDAO.getNumberOfAvailableCars(); return Response.status(200).entity("" + availableCars).build(); } }

Web application

The service is wired to the Jersey servlet in web.xml:


<web-app id="WebApp_ID" version="2.4" xmlns="" xmlns:xsi="" xsi:schemaLocation=""> <display-name>Restful Web Application</display-name> <servlet> <servlet-name>REST-servlet</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <init-param> <param-name></param-name> <param-value></param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>REST-servlet</servlet-name> <url-pattern>/rest/*</url-pattern> </servlet-mapping> </web-app>

Unit test

I wired the application together using this test:


package se.waymark.rentit; import org.junit.Test; import; import static; import static org.junit.Assert.assertThat; public class RentCarTest { @Test public void shouldRentACar() { int initialNumberOfCars = 43; RentCar rentCar = new RentCar(); rentCar.createCars(initialNumberOfCars); rentCar.rentCar(); int oneRentedCar = 1; Integer expected = initialNumberOfCars - oneRentedCar; String actualString = (String) rentCar.getAvailableCars().getEntity(); Integer actual = Integer.parseInt(actualString); assertThat(actual, is(expected)); } }


A simple RESTFul web service can be added on top of the model without changing the defined behaviour. This is Behaviour Driven Development. You define the behaviour you want. Implement it. Add an interface if it is needed but don’t change the behaviour if you don’t have to. Next exercise is to use the same behaviour but connect to it from a SOAP based web service. I will use a CXF based SOAP web service this time.

Next – A SOAP web service


  1. Hi Thomas,
    Have you published source code of your Cucumber posts anywhere ? If so, please pass on that Location.

    Comment by Ram — June 28, 2013 @ 15:19

    • Hi

      I haven’t published the source code anywhere. I think that you will learn more by typing the code yourself or by copying the code from the blog compared with getting the source from a zip or github. That is the reason why this code isn’t available anywhere.


      Comment by Thomas Sundberg — July 1, 2013 @ 22:14

      • Great idea about the “typing the code yourself” strategy. It’s true.

        On another note, I just started reading your blog for the first time. Excellent content, keep it up.

        – Paul

        Comment by Paul — January 3, 2014 @ 18:14

  2. Hi,

    I’ve been working my way thru your Cucumber tutorial series, they have been a great help!
    I asked a question on the “a jsf web application” regarding tomcat zip.
    I found a way to download the binary from maven repo (see bottom for details):

    I still have a couple of questions/issues with my setup:

    1) What maven command should I be running to start tomcat and run the integration tests

    ../rest-ws>mvn integration-test (tomcat is not starting for me, the same thing happened for the zip install)

    T E S T S
    Running se.waymark.rentit.RunCukesIT
    HTTP/1.1 404 Not Found

    If I start tomcat
    ../rest-ws>mvn tomcat:run (see output below)

    then run the Rent.feature via a cucumber-plugin inside eclipse, it works fine

    do you have any suggestions on what I am doing wrong and how I can correct it?

    2) Do you have any ideas on how to get jersey to log requests/responses?

    I did update my com.jayway.restassured dependency to 2.3.2
    and changed the RentACarSupport to use the new API.


    this gives me logging at the client, but I am still wondering if there is some logging
    i can do in Jersey.


    <<mvn tomcat:run >>>
    [INFO] Nothing to compile – all classes are up to date
    [INFO] <<< tomcat-maven-plugin:1.1:run (default-cli) < compile @ rest-main <<<
    [INFO] — tomcat-maven-plugin:1.1:run (default-cli) @ rest-main —
    [INFO] Running war on http://localhost:8080/rest-main
    [INFO] Using existing Tomcat server configuration at C:\Users\timr\.gitlablocal\workspaces\rest-ws\rest-main\target\tomcat
    Jul 11, 2014 2:33:56 PM org.apache.catalina.startup.Embedded start
    INFO: Starting tomcat server
    Jul 11, 2014 2:33:56 PM org.apache.catalina.core.StandardEngine start
    INFO: Starting Servlet Engine: Apache Tomcat/6.0.29
    Jul 11, 2014 2:33:57 PM com.sun.jersey.api.core.PackagesResourceConfig init
    INFO: Scanning for root resource and provider classes in the packages:
    Jul 11, 2014 2:33:57 PM com.sun.jersey.api.core.ScanningResourceConfig logClasses
    INFO: Root resource classes found:
    Jul 11, 2014 2:33:57 PM com.sun.jersey.api.core.ScanningResourceConfig init
    INFO: No provider classes found.
    Jul 11, 2014 2:33:57 PM com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
    INFO: Initiating Jersey application, version 'Jersey: 1.9 09/02/2011 11:17 AM'
    Jul 11, 2014 2:33:58 PM org.apache.coyote.http11.Http11Protocol init
    INFO: Initializing Coyote HTTP/1.1 on http-8080
    Jul 11, 2014 2:33:58 PM org.apache.coyote.http11.Http11Protocol start
    INFO: Starting Coyote HTTP/1.1 on http-8080

    Tomcat binary from Maven Repo:





    Comment by Tim — July 12, 2014 @ 02:34

    • Hi!

      To start Tomcat and run the integrations tests, do
      mvn integration-test

      I can’t really say that I know how you should enable logging request/response in Jersey. I would probably add log statements in my own methods and be happy to see them being called.


      Comment by Thomas Sundberg — July 12, 2014 @ 23:46

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at

%d bloggers like this: