Package

org.iainhull

resttest

Permalink

package resttest

Visibility
  1. Public
  2. All

Type Members

  1. trait Api extends AnyRef

    Permalink

    Provides the main api for creating and sending REST Web service requests (as a trait for mixing in).

  2. trait Dsl extends Api with Extractors

    Permalink

    Provides a DSL for simplifying REST system tests.

    Provides a DSL for simplifying REST system tests. This is meant to be used with ScalaTest or similar testing framework.

    For example to post a json document to a REST endpoint and check the statusCode:

    val personJson = """{ "name": "fred" }"""
    POST url "http://api.rest.org/person" body personJson asserting (statusCode is Status.Created)

    Or to get a json document from a REST endpoint and convert the json array to a List of Person objects:

    val people = GET url "http://api.rest.org/person" returning (jsonBodyAsList[Person])

    Finally a more complete example that using a ScalaTest Spec to verify a simple REST API.

    class DslSpec extends FlatSpec with Dsl {
      "An empty api" should "support adding and deleting a single object" {
        using (_ url "http://api.rest.org/person") { implicit rb =>
          GET asserting (statusCode is Status.OK, jsonBodyAsList[Person] is EmptyList)
          val id = POST body personJson asserting (statusCode is Status.Created) returning (header("X-Person-Id"))
          GET / id asserting (statusCode is Status.OK, jsonBodyAs[Person] is Jason)
          GET asserting (statusCode is Status.OK, jsonBodyAsList[Person] is Seq(Jason))
          DELETE / id asserting (statusCode is Status.OK)
          GET / id asserting (statusCode is Status.NotFound)
          GET asserting (statusCode is Status.OK, jsonBodyAsList[Person] is EmptyList)
        }
      }
    }

    Configuring a Request

    The DSL centers around the Api.RequestBuilder, which specifies the properties of the request. Most expressions begin with the HTTP Api.Method followed by a call to RichRequestBuilder, this converts the Method to a Api.RequestBuilder. The resulting RequestBuilder contains both the Method and secondary property. For example:

    GET url "http://api.rest.org/person"

    is the same as

    RequestBuilder().withMethod(GET).withUrl("http://api.rest.org/person")

    The RequestBuilder DSL also supports default values passed implicitly into expressions, for example:

    implicit val defaults = RequestBuilder() addHeader ("Accept", "application/json")
    GET url "http://api.rest.org/person"

    creates a RequestBuilder with a method, url and accept header set. The default values are normal expressed the with the using expression.

    Executing a Request

    There are three ways to execute a request: RichRequestBuilder.execute, RichResponse.returning, RichRequestBuilder.asserting, these can all be applied to RequestBuilder instances.

    The execute method executes the request with the implicit Api.HttpClient and returns the Response.

    val response: Response = GET url "http://api.rest.org/person" execute ()

    The returning method executes the request like the execute method, except it applies one or more Extractors to the Response to return only the extracted information.

    val code1 = GET url "http://api.rest.org/person" returning (StatusCode)
    val (code2, people) = GET url "http://api.rest.org/person" returning (StatusCode, jsonBodyAsList[Person])

    The asserting method executes the request like the execute method, except it verifies the specified value of one or more Response values. asserting is normally used with extractors, see [RichExtractor] for more information. asserting and returning methods can be used in the same expression.

    GET url "http://api.rest.org/person" asserting (statusCode is Status.OK)
    val people = GET url "http://api.rest.org/person" asserting (statusCode is Status.OK) returning (jsonBodyAsList[Person])

    Working with Extractors

    Extractors are simply functions that take a Api.Response are extract or convert part of its contents. Extracts are written to assume that the data they require is in the response, if it is not they throw an Exception (failing the test). See Extractors for more information on the available default Extractors And how to implement your own.

  3. trait Extractors extends AnyRef

    Permalink
  4. trait RestMatchers extends AnyRef

    Permalink

    Adds ScalaTest support to the RestTest Dsl.

    Adds ScalaTest support to the RestTest Dsl.

    The should keyword is added to Api.RequestBuilder and Api.Response expressions, the RequestBuilder is executed first and should applied to the Response.

    The have keyword supports Extractors.ExtractorLikes. See ExtractorToHavePropertyMatcher for more details.

    Example
    using (_ url "http://api.rest.org/person") { implicit rb =>
      GET should have (statusCode(Status.OK), jsonBodyAsList[Person] === EmptyList)
    
      val (status, id) = POST body personJson returning (statusCode, headerText("X-Person-Id"))
      status should be(Status.Created)
    
      val foo = GET / id should have (statusCode(Status.OK), jsonBodyAs[Person] === Jason)
    
      GET should have (statusCode === Status.OK, jsonBodyAsList[Person] === Seq(Jason))
    
      DELETE / id should have (statusCode === Status.OK)
    
      GET / id should have (statusCode === Status.NotFound)
    
      GET should have (statusCode(Status.OK), jsonBodyAsList[Person] === EmptyList)
    }
  5. trait TestDriver extends AnyRef

    Permalink

    The test driver defines the Api.HttpClient and initial Api.RequestBuilder used to execute Rest Tests.

    The test driver defines the Api.HttpClient and initial Api.RequestBuilder used to execute Rest Tests.

    Users mix-in their preferred TestDriver implementation, to execute their tests.

    class PersonSpec extends FlatSpec {
      this: TestDriver =>
    
      val EmptyList = Seq[Person]()
    
      "/person (collection)" should "be empty" in {
        GET / "person" asserting (StatusCode === Status.OK, BodyAsPersonList === EmptyList)
      }
    }
    
    class PersonUnitSpec extends PersonSpec with SprayUnitTestDriver with MyService
    
    class PersonSystemSpec extends PersonSpec with JerseySystemTestDriver {
      override val baseUrl = "http://localhost:9000"
    }

    Subclasses implement the interface supplying a httpClient to execute the Requests and a defBuilder which provides the base configuration for all tests. All tests should support relative paths, this enables the same test code to be executed as a unit test and a system test. To support this the defBuilder for system test drivers should supply the baseUrl some how.

Value Members

  1. object Api

    Permalink

    Provides the main api for creating and sending REST Web service requests (as an object for importing).

    Provides the main api for creating and sending REST Web service requests (as an object for importing).

    val request = Request(GET, new URI("http://api.rest.org/person", Map(), None))
    val response = driver.execute(request)
    response.statusCode should be(Status.OK)
    response.body match {
      Some(body) => objectMapper.readValue[List[Person]](body) should have length(0)
      None => fail("Expected a body"))
    }

    or using the Api.RequestBuilder

    val request = driver.execute(RequestBuilder().withUrl("http://api.rest.org/person/").withMethod(GET))

    This provides the basic interface used to implement the Dsl, users are expected to use the Dsl.

  2. object Dsl extends Dsl

    Permalink
  3. object Extractors

    Permalink
  4. object RestMatchers extends RestMatchers

    Permalink
  5. package driver

    Permalink

Ungrouped