REST-Assured Notes


Here are some notes on REST-assured as I feel the urge. This framework is in competition with the Jersey Test Framework.

Site and links

http://code.google.com/p/rest-assured/
Second tutorial: http://www.hascode.com/2011/09/rest-assured-vs-jersey-test-framework-testing-your-restful-web-services/

Sample static and other imports

Lots of Hamcrest when you do REST-assured.

import static org.hamcrest.Matchers.equalTo;
import static com.jayway.restassured.RestAssured.given;
import static com.jayway.restassured.RestAssured.expect;
import static com.jayway.restassured.matcher.RestAssuredMatchers.*

JARs

JAR developers take note: Could the JARs be less confusing? These guys have done it right!

Prerequisites

This is a snapshot of a one-time http://rest-assured.googlecode.com/files/rest-assured-dependencies.zip that contained these JARs which support REST-assured's JAR. Some are absolutely required; if others are absent you might get away with it at first, but later end up with some java.lang.NoClassDefFoundError for one of them that might have otherwise given you more information on what you're doing wrong.


Sample set-up

This is what I do underneath it all, then I call RestAssuredUtil.setup() from @Before public void setup().

package com.acme.web.service;

import com.jayway.restassured.RestAssured;
import com.acme.web.util.ApplicationProperties;

/**
 * Isolate set-up of REST-assured here in order not to have to change it
 * everywhere else.
 */
public class RestAssuredUtil
{
    public static final void setup()
    {
        RestAssured.baseURI  = "http://localhost";
        RestAssured.port     = ApplicationProperties.APPLICATION_PORT;
        RestAssured.basePath = "/acmewebservice/api/v1";
    }
}

Example

Here's a working example that tests a ReST service named "langserv".

package com.acme.web.service;

import static com.jayway.restassured.RestAssured.expect;
import static com.jayway.restassured.RestAssured.given;
import static com.jayway.restassured.RestAssured.get;
import static org.hamcrest.Matchers.equalTo;

import org.junit.Before;
import org.junit.Test;

import com.acme.entity.Language;
import com.jayway.restassured.RestAssured;
import com.jayway.restassured.path.json.JsonPath;

/**
 * Note: In order for these tests to run, langserv must be launched in Tomcat.
 *
 * The point of this test is to try out the REST-assured framework. While this
 * mostly works, it a) requires a running Tomcat and underlying database with
 * real data inside, and b) might not really be something we need to test.
 *
 * Advantages to REST-assured!
 *
 *   - Self-documenting.
 *   - Statement of what URIs are supported.
 *   - Statement of what HTTP Status Codes are returned.
 *
 * These tests are a little brittle?
 *
 * This may be a reason not to do them. What's brittle in this testing is confined
 * especially to PUT and DELETE: you must know the id of something to update and/or
 * delete. There is a way to get the new id created by the POST operation, via the
 * name of the new language. See the first few lines at the top of testUpdate() and
 * testDelete().
 *
 * If this test fails, it will be necessary to reinitialize the database from
 * scratch before it will work. Specifically, testUpdate() will fail when it's
 * invoked after testDelete() fails (or isn't run) since the result of
 * get( "/language/name/Zzyzzx" ) will not be a single language, but two or more,
 * something like:
 *
 * {
 *     "language":
 *     [
 *         {
 *             "code":"zz",
 *             "id":"175",
 *             "name":"Zzyzzx"
 *         },
 *         {
 *             "code":"zz",
 *             "id":"176",
 *             "name":"Zzyzzx"
 *         }
 *     ]
 * }
 *
 * @author Russell Bateman
 */
public class LanguageWSTest
{
    @Before
    public void setup()
    {
        RestAssuredUtil.setup();
    }

    @Test
    public void testCreate()
    {
        Language language = new Language();

        language.setCode( "zz" );
        language.setName( "Zzyzzx" );

//      Language response =            --this sort of thing is possible for saving...

        given().contentType( "application/json" )
               .and()
               .body( language )
       .when().post( "/language" );

//     Integer id = response.getId();  --...this id for use in update and delete below
    }

    /**
     * We expect to find language 35 (should be English) in the database.
     */
    @Test
    public void testRead()
    {
        expect().statusCode( 200 )
        .when() .get ( "/language/35" );
    }

    /**
     * We expect to find language 35 (should be English) in the database.
     */
    @Test
    public void testRead_byId()
    {
        expect().body( "id",   equalTo( "35" ) )
                .body( "name", equalTo( "English" ) )
                .body( "code", equalTo( "en" ) )
        .when() .get ( "/language/35" );
    }

    /**
     * We expect not to find language 0 in the database.
     */
    @Test
    public void testRead_byId_not_found()
    {
        expect().statusCode( 404 )
       .when()  .get ( "/language/0" );
    }

    /**
     * We expect to find language 35 (should be English) in the database.
     */
    @Test
    public void testReadByPropertyAndValue()
    {
        expect().body( "code", equalTo( "en" ) )
        .when() .get ( "/language/35" );
    }

    /**
     * We expect that testCreate() above added language 174 to the
     * database and that we can muck with it.
     */
    @Test
    public void testUpdate()
    {
        /* If this bit goes well, we should know the id of the new language we added,
         * in testCreate(), so we can feel free to update or delete it in these tests.
         */
        String   json = get( "/language/name/Zzyzzx" ).asString();
        String   id   = JsonPath.with( json ).get( "language.id" );

        Language language = new Language();

        language.setId( Integer.parseInt( id ) );
        language.setCode( "z0" );
        language.setName( "Zzyzzx" );

        given().contentType( "application/json")
                .and()
                .body( language )
       .when()  .put ( "/language/" + id );
    }

    /**
     * We expect that testCreate() above added a new language, "Zzyzzx" to the
     * database and that we can delete it.
     */
    @Test
    public void testDelete()
    {
        String   json = get( "/language/name/Zzyzzx" ).asString();
        String   id   = JsonPath.with( json ).get( "language.id" );

        expect().statusCode( 200 )
        .when() .delete( "/language/" + id );
    }
}