1. Introduction

REST Assured は、REST ベースのサービスに対するテストを簡単に記述できる、HTTP Builder で構築された Java 専用の DSL です。
さまざまな HTTP メソッド(POST、GET、PUT、DELETE、OPTIONS、PATCH、HEAD)のリクエストに対するレスポンスを確認、検証できます。

1.1. static imoprt

REST Assured を効率的に使うには、次のような import 文を記述するといいでしょう。

import static io.restassured.RestAssured.*;
import static io.restassured.matcher.RestAssuredMatchers.*;
import static org.hamcrest.Matchers.*;

Json Schema のバリデーション機能を使うには、次のような import 文も追加するといいでしょう。

import static io.restassured.module.jsv.JsonSchemaValidator.*;

詳しくは Json Schema Validation のセクションを参照してください。

あなたのアプリケーションが Spring MVC を使っているなら、Spring Mock MVC モジュールを使えば、コントローラークラスのユニットテストを REST Assured の DSL で記述できます。
その場合、io.restassured.RestAssured の代わりに RestAssuredMockMvc を import 文に記述します。

import static io.restassured.module.mockmvc.RestAssuredMockMvc.*;

2. Examples

2.1. Example 1 - JSON

http:/localhost:8080/lotto に対する GET リクエストが次のような JSON を返すことにします。

{
  "lotto":{
    "lottoId":5,
    "winning-numbers":[2,45,34,23,7,5,3],
    "winners":[
      {
        "winnerId":23,
        "numbers":[2,45,34,23,3,5]
      },
      {
        "winnerId":54,
        "numbers":[52,3,12,11,18,22]
      }
    ]
  }
}

REST Assured で、GET リクエストに対するレスポンスの lottoId5 になることを検証するときは次のように記述します。とても簡単です。

    get("/lotto")
    .then()
        .body("lotto.lottoId", equalTo(5));

winnerId2324 が入っていることを確認するときは次のように記述します。

    get("/lotto")
    .then()
        .body("lotto.winners.winnerId", hasItems(23, 54));

注意:equalTohasItems は Hamcrest ライブラリのマッチャーメソッドなので、org.hamcrest.Matchers の import 文を追加する必要があります。

JSONPath の記法として、 Jayway の JsonPath ではなく、 Groovy の GPath を使っているので、間違えないようにしてください。

2.1.1. Returning floats and doubles as BigDecimal

REST Assured では、設定により JSONPath で指定した json number の値を floatdouble ではなく BigDecimal として処理できます。
次のような JSON ドキュメントがあることにしましょう。

{

    "price": 12.12

}

初期設定では、price の値は float12.12 と比較できます。

    get("/price")
    .then()
        .body("price", is(12.12f));

JsonConfig オブジェクトを次のように設定すれば、全ての json number の値を BigDecimal で比較できるようになります。

    given()
        .config(
            RestAssured.config().jsonConfig(
                jsonConfig().numberReturnType(BIG_DECIMAL)))
    .when()
        .get("/price")
    .then()
        .body("price", is(new BigDecimal(12.12));

2.1.2. JSON Schema validation

REST Assured はバージョン 2.1.0 から Json Schema のバリデーションに対応しました。
例えば、次のようなスキーマを記述した products-schema.json がクラスパスにあることにしましょう。

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "Product set",
    "type": "array",
    "items": {
        "title": "Product",
        "type": "object",
        "properties": {
            "id": {
                "description": "The unique identifier for a product",
                "type": "number"
            },
            "name": {
                "type": "string"
            },
            "price": {
                "type": "number",
                "minimum": 0,
                "exclusiveMinimum": true
            },
            "tags": {
                "type": "array",
                "items": {
                    "type": "string"
                },
                "minItems": 1,
                "uniqueItems": true
            },
            "dimensions": {
                "type": "object",
                "properties": {
                    "length": {"type": "number"},
                    "width": {"type": "number"},
                    "height": {"type": "number"}
                },
                "required": ["length", "width", "height"]
            },
            "warehouseLocation": {
                "description": "Coordinates of the warehouse with the product",
                "$ref": "http://json-schema.org/geo"
            }
        },
        "required": ["id", "name", "price"]
    }
}

次のように記述すると、JSON スキーマで、リソース /products から取得した JSON ドキュメントを検証できます。

    get("/products")
    .then()
        .assertThat()
        .body(matchesJsonSchemaInClasspath("products-schema.json"));

matchesJsonSchemaInClasspathio.restassured.module.jsv.JsonSchemaValidator のクラスメソッドです。
全てのクラスメソッドを static import しておくことをお勧めします。
この機能を使用するには、 json-schema-validator モジュールを Maven の依存ライブラリへ追加しなければなりません。

    <dependency>
        <groupId>io.rest-assured</groupId>
        <artifactId>json-schema-validator</artifactId>
        <version>4.4.0</version>
    </dependency>

2.1.3. JSON Schema Validation Settings

REST Assured の json-schema-validator モジュールは、Francis Galiegue の json-schema-validator ライブラリ(以降は fge と呼びます)を使用してバリデーションを行います。
fge ライブラリの設定を変更するときは次のように記述してください。

    // Given
    JsonSchemaFactory jsonSchemaFactory = JsonSchemaFactory.newBuilder()
        .setValidationConfiguration(
            ValidationConfiguration.newBuilder()
                .setDefaultVersion(DRAFTV4).freeze())
        .freeze();

    // When
    get("/products")
    .then()
        .assertThat()
        .body(matchesJsonSchemaInClasspath("products-schema.json")
            .using(jsonSchemaFactory));

バリデーションに使用する jsonSchemaFactory のインスタンスは using メソッドで指定できます。
バリデーションの内容をより細かく調整したいときに使用してください。

fge ライブラリは checkedunchecked の2種類のバリデーションを使用できます。
初期設定では checked バリデーションを使用しますが、unchecked バリデーションを使用したいときは JsonSchemaValidatorSettings のインスタンスを構成してください。

    get("/products")
    .then()
        .assertThat()
        .body(matchesJsonSchemaInClasspath("products-schema.json")
            .using(settings().with().checkedValidation(false)));

settingsJsonSchemaValidatorSettings のクラスメソッドです。

2.1.4. Json Schema Validation with static configuration

常に unchecked バリデーションを使用すると同時に、JSON スキーマのバージョン 3 を使用するようにしたい場合は、毎回設定する代わりに、クラスメンバ変数で設定できるようになっています。

    JsonSchemaValidator.settings = settings().with().jsonSchemaFactory(
        JsonSchemaFactory.newBuilder().setValidationConfiguration(
            ValidationConfiguration.newBuilder()
                .setDefaultVersion(DRAFTV3).freeze())
        .freeze())
    .and()
    .with()
        .checkedValidation(false);

    get("/products")
    .then()
        .assertThat()
        .body(matchesJsonSchemaInClasspath("products-schema.json"));

JsonSchemaValidator のクラスメンバ変数 settings を変更すると、JsonSchemaValidator からインポートした全ての matcher メソッドが DRAFTV3 バージョンと unchecked バリデーションを使うようになります。

JsonSchemaValidator を初期設定へ戻すには rest メソッドを呼び出します。

    JsonSchemaValidator.reset();

2.1.5. Json Schema Validation without REST Assured

json-schema-validator モジュールは単独で使用することもできます。
JSON ドキュメントが String になっているなら次のように記述できます。

import org.junit.Test;
import static io.restassured.module.jsv.JsonSchemaValidator.matchesJsonSchemaInClasspath;
import static org.hamcrest.MatcherAssert.assertThat;

public class JsonSchemaValidatorWithoutRestAssuredTest {


    @Test public void
    validates_schema_in_classpath() {
        // Given
        String json = ... // Greeting response

        // Then
        assertThat(json, matchesJsonSchemaInClasspath("greeting-schema.json"));
    }
}

詳しくは REST Assured 入門 を参照してください。

2.1.6. Anonymous JSON root validation

JSON ドキュメントの中には名前付きのルート属性がない場合もあります。
例えば、次のコードは正しい JSON ドキュメントです。

[1, 2, 3]

JSONPath に $ あるいは空文字列を指定すると、匿名のルート要素を確認できます。
例えば http:/localhost:8080/json が前のような JSON ドキュメントを返すとしたら、次のように検証できます。

    when()
        .get("/json")
    .then()
        .body("$", hasItems(1, 2, 3));
        // An empty string "" would work as well
        // .body("", hasItems(1, 2, 3));

2.2. Example 2 - XML

XML ドキュメントも同じように確認できます。
http://localhost:8080/greetXML に対する POST リクエストが次のようなレスポンスを返すことにしましょう。

<greeting>
   <firstName>{params("firstName")}</firstName>
   <lastName>{params("lastName")}</lastName>
</greeting>

注意:このURLで公開しているのは、リクエストパラメータで送信した firstNamelastName をそのまま送り返すサービスだと考えてください。

リクエストパラメータで送信した firstName に対応するレスポンスは次のように検証できます。

    given()
        .parameters("firstName", "John", "lastName", "Doe")
    .when()
        .post("/greetXML")
    .then()
        .body("greeting.firstName", equalTo("John"));

firstNamelastName を両方とも検証するときは次のように記述します。

    given()
        .parameters("firstName", "John", "lastName", "Doe")
    .when()
        .post("/greetXML")
    .then()
        .body("greeting.firstName", equalTo("John"))
        .body("greeting.lastName", equalTo("Doe"));

省略記法も使用できます。

    with()
        .parameters("firstName", "John", "lastName", "Doe")
    .when()
        .post("/greetXML")
    .then()
        .body("greeting.firstName", equalTo("John"),
            "greeting.lastName", equalTo("Doe"));

フィールドを指定する記法について詳しくは Groovy の GPath を参照してください。

2.2.1. XML namespaces

レスポンス本文の期待値に名前空間を指定するときは、 io.restassured.config.XmlConfig で名前空間を宣言しなければなりません。
具体例として、http://localhost:8080 で提供しているリソース namespace-example が次のような XML ドキュメントを返すことにします。

<foo xmlns:ns="http://localhost/">
  <bar>sudo </bar>
  <ns:bar>make me a sandwich!</ns:bar>
</foo>

URI http://localhost/ を名前空間として宣言し、XML ドキュメントを検証するには、次のように記述します。

    given()
        .config(
            RestAssured.config().xmlConfig(
                xmlConfig()
                    .declareNamespace("test", "http://localhost/")))
    .when()
        .get("/namespace-example")
     .then()
        .body("foo.bar.text()", equalTo("sudo make me a sandwich!"))
        .body(":foo.:bar.text()", equalTo("sudo "))
        .body("foo.test:bar.text()", equalTo("make me a sandwich!"));

この例で使用しているパス記法は、Groovy の XmlSlurper 記法です(2.6.0 より前のバージョンでは XmlSlurper 記法を使えません)。
2.6.0 より前のバージョンで使用できる記法を知りたければ リリースノートの後方互換性に関する記述 を参照してください。

2.2.2. XPath

XML ドキュメントは XPath で確認することもできます。

    given()
        .parameters("firstName", "John", "lastName", "Doe")
    .when()
        .post("/greetXML")
    .then()
        .body(hasXPath("/greeting/firstName", containsString("Jo")));

別の書き方も出来ます。

    given()
        .parameters("firstName", "John", "lastName", "Doe")
    .when()
        .post("/greetXML")
    .then()
        .body(hasXPath("/greeting/firstName[text()='John']"));

XPath で名前空間を使用するときは、XmlConfig で有効化しなければなりません。

    given()
        .config(
            RestAssured.config().xmlConfig(
                xmlConfig()
                    .with()
                    .namespaceAware(true)))
    .when()
        .get("/package-db-xml")
    .then()
        .body(hasXPath("/db:package-database", namespaceContext));

namespaceContextjavax.xml.namespace.NamespaceContext のインスタンスです。

2.2.3. Schema and DTD validation

XML ドキュメントの検証に XML スキーマ(XSD)や DTD を使うこともできます。

XSD example
    get("/carRecords")
    .then()
        .assertThat()
        .body(matchesXsd(xsd));
DTD example
    get("/videos")
    .then()
        .assertThat()
        .body(matchesDtd(dtd));

matchesXsdmatchesDtdio.restassured.matcher.RestAssuredMatchers のクラスメソッドで、Hamcrest マッチャーです。

2.3. Example 3 - Complex parsing and validation

REST Assured が特に際立つ使い方を説明しましょう。
REST Assured は Groovy で実装しているので、Groovy のコレクション API の素晴らしいところがそのまま利点になっています。
Groovy の例を見てみましょう。

def words = ['ant', 'buffalo', 'cat', 'dinosaur']
def wordsWithSizeGreaterThanFour = words.findAll { it.length() > 4 }

1行目は単語(文字列)のリストを定義しているだけですが、2行目はちょっと面白いことをしています。
単語のリストから4文字以上の単語を探索するため、findAll メソッドに4文字以上が真になる式をクロージャで渡しているのです。
クロージャの内部では暗黙的な変数 it がリストの要素になります。
新しいリスト wordsWithSizeGreaterThanFour には buffalodinosaur が含まれることになります。

Groovy のコレクションには、他にもいろんなメソッドがあります。

  • find — クロージャの式が真になる最初の要素を探索します

  • collect — それぞれの要素についてクロージャを評価した結果を返します

  • sum — コレクションの全ての要素を加算します

  • max/min — コレクションの全ての要素について最大あるいは最小の要素を返します

JSON ドキュメントや XML ドキュメントをバリデーションするのに、これらの API がどのように使われているのか説明しましょう。

2.3.1. XML Example

http://localhost:8080/shopping が次のような XML ドキュメントを返すことにします。

<shopping>
      <category type="groceries">
        <item>Chocolate</item>
        <item>Coffee</item>
      </category>
      <category type="supplies">
        <item>Paper</item>
        <item quantity="4">Pens</item>
      </category>
      <category type="present">
        <item when="Aug 10">Kathryn's Birthday</item>
      </category>
</shopping>

このような XML ドキュメントについて、種類(type)が食料品(groceries)、内容(items)にチョコレート(Chocolate)とコーヒー(Coffee)を含むカテゴリー(category)があることを確かめるには、次のように記述します。

    when()
        .get("/shopping")
    .then()
        .body("shopping.category.find { it.@type == 'groceries' }.item", hasItems("Chocolate", "Coffee"));

詳しく見ていきましょう。
XPath に指定した shopping.category はカテゴリーのリストを返します。
そして、カテゴリーのリストに対する findtype 属性が groceries に一致する最初のカテゴリーを返します。
それから、発見したカテゴリーに関連付けられた全ての item を返します。
最終的に1つ以上の item からなるリストを hasItems マッチャーで検証します。

item を取得するだけで、検証したいわけではないとしたらどうすればいいでしょうか。
そういうときは XmlPath を使用します。

// Get the response body as a String
String response = get("/shopping").asString();
// And get the groceries from the response. "from" is statically imported from the XmlPath class
List<String> groceries = from(response).getList("shopping.category.find { it.@type == 'groceries' }.item");

レスポンス本文について、食料品(groceries)のリストだけを処理したい場合は ショートカット することもできます。

// Get the response body as a String
List<String> groceries = get("/shopping").path("shopping.category.find { it.@type == 'groceries' }.item");

前に説明した内容は次のような省略記法でも実現できます。

    when()
        .get("/shopping")
    .then()
        .body("**.find { it.@type == 'groceries' }", hasItems("Chocolate", "Coffee"));

*\* は XML ドキュメントについて深さ優先探索をする省略記法です。
type 属性が groceries に一致する最初のノードを検索できます。
XPath に item を書いてないことに注目してください。
それぞれのカテゴリーノードについて item のリストを返すとき、自動的に toString() メソッドが呼び出されるからです。

2.3.2. JSON Example

http://localhost:8080/store が次のような JSON ドキュメントを返すことにします。

{
   "store":{
      "book":[
         {
            "author":"Nigel Rees",
            "category":"reference",
            "price":8.95,
            "title":"Sayings of the Century"
         },
         {
            "author":"Evelyn Waugh",
            "category":"fiction",
            "price":12.99,
            "title":"Sword of Honour"
         },
         {
            "author":"Herman Melville",
            "category":"fiction",
            "isbn":"0-553-21311-3",
            "price":8.99,
            "title":"Moby Dick"
         },
         {
            "author":"J. R. R. Tolkien",
            "category":"fiction",
            "isbn":"0-395-19395-8",
            "price":22.99,
            "title":"The Lord of the Rings"
         }
      ]
   }
}
Example 1

1つ目の例は、/store にリクエストを送信し、レスポンスについて価格(price)が10未満の本(book)の書名(title)が "Sayings of the Century" と "Moby Dick" であることを検証する場合です。

    when()
        .get("/store")
    .then()
        .body("store.book.findAll { it.price < 10 }.title", hasItems("Sayings of the Century", "Moby Dick"));

XML ドキュメントと同様に、価格が10未満なら真になる式を評価するクロージャで、全ての本を探索します。
そして hasItems マッチャーで期待値と比較します。
JsonPath を使うと title のリストを取得できます。

// Get the response body as a String
String response = get("/store").asString();
// And get all books with price < 10 from the response. "from" is statically imported from the JsonPath class
List<String> bookTitles = from(response).getList("store.book.findAll { it.price < 10 }.title");
Example 2

2つ目の例として、著者名の文字列長の合計が50を越えるかどうかを検証してみましょう。
少し複雑な目的のため、Groovy のコレクションとクロージャの組み合わせの強力さを説明するちょうどいい例になっているでしょう。

     when()
         .get("/store")
     .then()
         .body("store.book.author.collect { it.length() }.sum()", greaterThan(50));

store.book.author は全ての著者名のリストになります。
そして著者名のリストに collect メソッドでクロージャ { it.length() } を適用し、著者名の文字列長のリストを取得します。
それから文字列長のリストに sum() メソッドを呼び出して、文字列長の合計を計算します。
最後に greaterThan マッチャーで文字列長の合計が 53 を越えるか検証します。
実はこの記述も省略できます。
"word" の例で説明します。

def words = ['ant', 'buffalo', 'cat', 'dinosaur']

Groovy では展開演算子(spread operator) \* でリストのそれぞれの要素に関数を呼び出すことができます。

def words = ['ant', 'buffalo', 'cat', 'dinosaur']
assert [3, 6, 3, 8] == words*.length()

展開演算子を使うと、前のコード例は次のように記述できます。

    when()
        .get("/store")
    .then()
        .body("store.book.author*.length().sum()", greaterThan(50));

もちろん、 JsonPath で値を取得することもできます。

// Get the response body as a string
String response = get("/store").asString();
// Get the sum of all author length's as an int. "from" is again statically imported from the JsonPath class
int sumOfAllAuthorLengths = from(response).getInt("store.book.author*.length().sum()");
// We can also assert that the sum is equal to 53 as expected.
assertThat(sumOfAllAuthorLengths, is(53));

2.4. Deserialization with Generics

REST Assured 3.3.0 では io.restassured.mapper.TypeRef クラスを導入しました。
これは、レスポンスを総称型のコンテナへ分解するために使用します。
例えば、/products に対する GET リクエストが次のような JSON ドキュメントを返すことにしましょう。

[
          {
              "id": 2,
              "name": "An ice sculpture",
              "price": 12.50,
              "tags": ["cold", "ice"],
              "dimensions": {
                  "length": 7.0,
                  "width": 12.0,
                  "height": 9.5
              },
              "warehouseLocation": {
                  "latitude": -78.75,
                  "longitude": 20.4
              }
          },
          {
              "id": 3,
              "name": "A blue mouse",
              "price": 25.50,
                  "dimensions": {
                  "length": 3.1,
                  "width": 1.0,
                  "height": 1.0
              },
              "warehouseLocation": {
                  "latitude": 54.4,
                  "longitude": -32.7
              }
          }
      ]

TypeRef を使うと、このドキュメントのルート要素を List<Map<String, Object>> へ変換できます(これ以外にも任意の総称型コンテナへ変換できます)。

// Extract
List<Map<String, Object>> products = get("/products").as(new TypeRef<List<Map<String, Object>>>() {});

// Now you can do validations on the extracted objects:
assertThat(products, hasSize(2));
assertThat(products.get(0).get("id"), equalTo(2));
assertThat(products.get(0).get("name"), equalTo("An ice sculpture"));
assertThat(products.get(0).get("price"), equalTo(12.5));
assertThat(products.get(1).get("id"), equalTo(3));
assertThat(products.get(1).get("name"), equalTo("A blue mouse"));
assertThat(products.get(1).get("price"), equalTo(25.5));```

この機能は今のところ JSON ドキュメントにしか使用できないので注意してください。

2.5. Additional Examples

Micha Kops がhttp://www.hascode.com/2011/10/testing-restful-web-services-made-easy-using-the-rest-assured-framework/[さまざまな具体例を説明するよいブログ記事]を書いています。

また、 Bas Dijkstra は自身の主催している REST Assured の活用ワークショップをオープンソースとして GitHub リポジトリで惜しみなく公開してくれているので、誰でも試すことができるし、誰でも貢献できるようになっています。

Bas Dijkstra は、他にも REST Assured を紹介する素敵なスクリーンキャストを公開しています。

2.6. Note on floats and doubles

浮動小数点数は Java の基本型の float と比較しなければなりません。
例えば、次のような JSON オブジェクトがあることにしましょう。

{

    "price": 12.12

}

the following test will fail, because we compare with a "double" instead of a "float":
次のテストは、float じゃなくて double で比較しているため失敗してします。

get("/price").then().assertThat().body("price", equalTo(12.12));

float と比較すれば成功します。

get("/price").then().assertThat().body("price", equalTo(12.12f));

2.7. Note on syntax

REST Assured のブログ記事に登場するコード例では given/expect/when という記法がたくさん使われています。

    given()
        .param("x", "y")
    .expect()
        .body("lotto.lottoId", equalTo(5))
    .when()
        .get("/lotto");

これは「レガシー記法」と呼ばれるもので、REST Assured 1.x でテストを記述するための、事実上の標準になっている記法でした。
最新バージョンでも正常に動作するので、何が正しいかを巡って多くのユーザーを混乱させています。

最初に given/when/then 記法を使わなかったのは純粋に技術的な問題があったからです。
REST Assured 2.0 が出るまで given/when/then 記法に対応しなかったのは、BDD スタイルのテストとして標準的な方法とは言えない状況だったからです。
その頃は given/expect/when 記法がそれなりに存在感を示していたのですが、しばらくすると given/when/then 記法の分かりやすさが認知され始め、大半の場合に使われる記法になっていきました。

given/expect/when 記法には given/when/then 記法にない良いところがあります。
それは、期待値に対する全てのエラーを同時に表示できるところです(最後に期待値を書く記法だとできない)。

例えば、前のコード例にステータスコードの期待値を追加したら次のようになります。

    given()
        .param("x", "y")
    .expect()
        .statusCode(400)
        .body("lotto.lottoId", equalTo(6))
    .when()
        .get("/lotto");

この場合、REST Assured はステータスコードとレスポンス本文それぞれの期待値との不一致を報告します。
これを given/when/then 記法で書いてみましょう。

    given()
        .param("x", "y")
    .when()
        .get("/lotto")
    .then()
        .statusCode(400)
        .body("lotto.lottoId", equalTo(6));

この場合、REST Assured はステータスコードの期待値との不一致だけを報告します。
2つ目の期待値を確認するには、もう1度テストを実行しなければならないのです。

2.7.1. Syntactic Sugar

REST Assured を使う上で、いろいろ用意されている糖衣構文のことを説明しておくべきでしょう。
例えば、複数の要素を1行で記述するとき、and メソッドがあると可読性が高まります。

given().param("x", "y").and().header("z", "w").when().get("/something").then().assertThat().statusCode(200).and().body("x.y", equalTo("z"));

これは次のように記述したのと同じです。

    given()
        .param("x", "y")
        .header("z", "w")
    .when()
        .get("/something")
    .then()
        .statusCode(200)
        .body("x.y", equalTo("z"));

3. Getting Response Data

レスポンス本文を取得できます。
例えば、/lotto への GET リクエストに対して、次のようにレスポンス本文を取得できます。

InputStream stream = get("/lotto").asInputStream(); // Don't forget to close this one when you're done
byte[] byteArray = get("/lotto").asByteArray();
String json = get("/lotto").asString();

3.1. Extracting values from the Response after validation

レスポンスを検証した後でも、extract メソッドでレスポンスのインスタンスやレスポンス本文を取得できます。
後続のリクエストで使いたい値がレスポンスに含まれているときは便利な機能です。
例えば、/title リソースが次のような JSON ドキュメントを返すことにしましょう。

 {
     "title" : "My Title",
      "_links": {
              "self": { "href": "/title" },
              "next": { "href": "/title?page=2" }
           }
 }

コンテンツタイプが JSON であることと、titleMy Title であることを確認してから、次にリクエストを送信するためのリンクを next から取得しなければならないとします。
その場合は次のように記述できます。

String nextTitleLink =
    given()
        .param("param_name", "param_value")
    .when()
        .get("/title")
    .then()
        .contentType(JSON)
        .body("title", equalTo("My Title"))
    .extract()
        .path("_links.next.href");

get(nextTitleLink). ..

複数の値を抽出しなければならない場合はレスポンス全体のインスタンスを取得することもできます。

Response response =
    given().
        .param("param_name", "param_value")
    .when()
        .get("/title")
    .then()
        .contentType(JSON)
        .body("title", equalTo("My Title"))
    .extract()
        .response();

String nextTitleLink = response.path("_links.next.href");
String headerValue = response.header("headerName");

3.2. JSON (using JsonPath)

レスポンス本文があれば JsonPath で自由に値を取得できます。

int lottoId = from(json).getInt("lotto.lottoId");
List<Integer> winnerIds = from(json).get("lotto.winners.winnerId");

こちらの書き方のほうが効率的です。

JsonPath jsonPath = new JsonPath(json).setRoot("lotto");
int lottoId = jsonPath.getInt("lottoId");
List<Integer> winnerIds = jsonPath.get("winners.winnderId");

JsonPath は REST Assured が無くても使用できます。
詳しくは REST Assured 入門 を参照してください。

3.2.1. JsonPath Configuration

JsonPath がオブジェクトをデシリアライズする振る舞いは変更できます。

JsonPath jsonPath = new JsonPath(SOME_JSON).using(new JsonPathConfig("UTF-8"));

JsonPath の全てのインスタンスが共有するクラスメンバ変数で全体の設定を変更することもできます。

JsonPath.config = new JsonPathConfig("UTF-8");

JsonPath について詳しくは Jayway のブログ記事 を参照してください。

ただし、JsonPath の実装はhttps://github.com/jayway/JsonPath[Jayway の JsonPath] ではなく、 Groovy の GPath を使っているので、間違えないようにしてください。

3.3. XML (using XmlPath)

XmlPath を使うと REST Assured と同じような操作ができます。

String xml = post("/greetXML?firstName=John&lastName=Doe").andReturn().asString();
// Now use XmlPath to get the first and last name
String firstName = from(xml).get("greeting.firstName");
String lastName = from(xml).get("greeting.firstName");

// or a bit more efficiently:
XmlPath xmlPath = new XmlPath(xml).setRoot("greeting");
String firstName = xmlPath.get("firstName");
String lastName = xmlPath.get("lastName");

XmlPath は REST Assured が無くても使用できます。
詳しくは REST Assured 入門 を参照してください。

3.3.1. XmlPath Configuration

XmlPath がオブジェクトをデシリアライズする振る舞いは変更できます。

XmlPath xmlPath = new XmlPath(SOME_XML).using(new XmlPathConfig("UTF-8"));

XmlPath の全てのインスタンスが共有するクラスメンバ変数で全体の設定を変更することもできます。

XmlPath.config = new XmlPathConfig("UTF-8");

XmlPath について詳しくは Jayway のブログ記事 を参照してください。

3.3.2. Parsing HTML with XmlPath

XmlPathHTML互換モード を設定すると、XmlPath の記法(GPath)で HTML ページをパースできるようになります。
例えば、次のような HTML ドキュメントについて title 要素を取得したい場合について考えてみましょう。

<html>
<head>
    <title>my title</title>
  </head>
  <body>
    <p>paragraph 1</p>
     <br>
    <p>paragraph 2</p>
  </body>
</html>

XmlPath は次のように設定しておきましょう。

String html = ...
XmlPath xmlPath = new XmlPath(CompatibilityMode.HTML, html);

そうすると、title 要素は次のように取得できます。

xmlPath.getString("html.head.title"); // will return "mytitle"

この例を実行するには io.restassured.path.xml.XmlPath.CompatibilityMode.HTML を static import しておく必要があります。

3.4. Single path

1つのリクエストに対して1つのパスだけが必要な場合は、次のような省略記法が利用できます。

int lottoId = get("/lotto").path("lotto.lottoid");

REST Assured はレスポンスのコンテンツタイプから JsonPathXmlPath のどちらを使用するのか自動的に判断します。
コンテンツタイプが存在しない場合は既定のパーサーの設定を参照します。
どちらを使用するのか明示的に指定することもできます。

String firstName = post("/greetXML?firstName=John&lastName=Doe").andReturn().xmlPath().getString("firstName");

指定できる選択肢は xmlPathjsonPathhtmlPath です。

3.5. Headers, cookies, status etc

HTTP ヘッダーや HTTP Cookie、ステータスラインやステータスコードを取得できます。

Response response = get("/lotto");

// Get all headers
Headers allHeaders = response.getHeaders();
// Get a single header value:
String headerName = response.getHeader("headerName");

// Get all cookies as simple name-value pairs
Map<String, String> allCookies = response.getCookies();
// Get a single cookie value:
String cookieValue = response.getCookie("cookieName");

// Get status line
String statusLine = response.getStatusLine();
// Get status code
int statusCode = response.getStatusCode();

3.6. Multi-value headers and cookies

A header and a cookie can contain several values for the same name.
HTTP ヘッダーや HTTP Cookie は同じキーに複数の値を含む場合があります。

3.6.1. Multi-value headers

HTTP ヘッダーの全ての値を取得するには、最初に Response から Headers を取得します。
Headers のインスタンスメソッド Headers.getValues(<header name>) は全ての値の List を返します。

3.6.2. Multi-value cookies

HTTP ヘッダーの全ての値を取得するには、最初に Response から Cookies を取得します。
Cookies のインスタンスメソッド Cookies.getValues(<header name>) は全ての値の List を返します。

3.7. Detailed Cookies

Response.getDetailedCookie(java.lang.String) メソッドを使うと、コメント、パス、有効期限等の詳細な情報を全て含む、指定した名前の HTTP Cookie を取得できます。

Response.getDetailedCookies() メソッドを使うと、コメント、パス、有効期限等の詳細な情報を全て含む、全ての HTTP Cookie を取得できます。

4. Specifying Request Data

リクエストオブジェクトには、リクエストパラメータと共に HTTP ヘッダーや HTTP Cookie、リクエストボディやコンテンツタイプを指定できます。

4.1. Invoking HTTP resources

基本的には リクエストの仕様 に定義された "HTTP リクエストメソッド" を呼び出すことでリクエストを送信できるようになっています。

when().get("/x"). ..;

この get は HTTP リクエストメソッドです。

REST Assured 3.0.0 からは、 request メソッドに指定した任意の HTTP 述語でリクエストを送信できるようになりました。

    when()
        .request("CONNECT", "/somewhere")
    .then()
        .statusCode(200);

このコード例では CONNECT リクエストをサーバーに送信します。

4.2. Parameters

リクエストパラメータは次のように指定します。

    given()
        .param("param1", "value1")
        .param("param2", "value2")
    .when()
        .get("/something");

REST Assured は HTTP リクエストメソッドに応じて、リクエストパラメータの種類(クエリパラメータやフォームパラメータ)を自動的に判断します。
この例では GET リクエストなのでクエリパラメータになります。
POST リクエストの場合はフォームパラメータになります。
PUT リクエストや POST リクエストではクエリパラメータをフォームパラメータを使い分ける必要があるため、次のように記述します。

    given()
        .formParam("formParamName", "value1")
        .queryParam("queryParamName", "value2")
    .when()
        .post("/something");

URL に直接クエリパラメータを埋め込むこともできます。

    .when()
        .get("/name?firstName=John&lastName=Doe");

マルチパート形式のパラメータを送信する方法は マルチパートフォームデータ を参照してください。

4.2.1. Multi-value parameter

同じパラメータ名で複数の値を送信する場合は、それぞれの値を可変長引数として指定します。

given().param("myList", "value1", "value2"). ..

リストでも指定できます。

List<String> values = new ArrayList<String>();
values.add("value1");
values.add("value2");

given().param("myList", values). ..

4.2.2. No-value parameter

パラメータ名だけを指定すると値を送信しないようにできます。

given().param("paramName"). ..

4.2.3. Path parameters

リクエストを送信するURLにパスパラメータを埋め込むことができます。

post("/reserve/{hotelId}/{roomNumber}", "My Hotel", 23);

REST Assured では前のコード例のような使い方を "名前無しパスパラメータ" と呼び、添え字で参照します(最初のプレースホルダは "My Hotel" なので hotelId には "My Hotel" が入ります)。

名前有りパスパラメータもあります。

    given()
        .pathParam("hotelId", "My Hotel")
        .pathParam("roomNumber", 23)
    .when().
        .post("/reserve/{hotelId}/{roomNumber}")
    .then()
             ..

パスパラメータを使うとリクエストURLを読みやすくなるし、複数のテストで再利用しやすくなります。

REST Assured 2.8.0 から、名前無しパスパラメータと名前有りパスパラメータを混在して利用できるようになりました。

given().
        pathParam("hotelId", "My Hotel").
when().
        post("/reserve/{hotelId}/{roomNumber}", 23).
then().
         ..

この場合、rototNumber23 になります。

パスパラメータの数と、パラメータに指定した値の数が一致しないとエラーになります。
filterでは、パスパラメータの追加や変更や削除(冗長なパラメータの削除等)を伴うより高度な使い方を説明しています。

4.3. Cookies

HTTP Cookie を指定する最も簡単なやり方は次のとおりです。

given().cookie("username", "John").when().get("/cookie").then().body(equalTo("username"));

複数の HTTP Cookie を指定することもできます。

given().cookie("cookieName", "value1", "value2"). ..

前のコード例は2つの HTTP Cookie を作成します(cookieName=value1cookieName=value2)。

HTTP Cookie の詳細情報を指定するときは次のように記述します。

Cookie someCookie = new Cookie.Builder("some_cookie", "some_value").setSecured(true).setComment("some comment").build();
given().cookie(someCookie).when().get("/cookie").then().assertThat().body(equalTo("x"));

複数の HTTP Cookie を同時に指定できます。

Cookie cookie1 = Cookie.Builder("username", "John").setComment("comment 1").build();
Cookie cookie2 = Cookie.Builder("token", 1234).setComment("comment 2").build();
Cookies cookies = new Cookies(cookie1, cookie2);
given().cookies(cookies).when().get("/cookie").then().body(equalTo("username, token"));

4.4. Headers

given().header("MyHeader", "Something").and(). ..
given().headers("MyHeader", "Something", "MyOtherHeader", "SomethingElse").and(). ..

HTTP ヘッダーには複数の値を設定できます。

given().header("headerName", "value1", "value2"). ..

前のコード例は2つの HTTP ヘッダーを作成します(headerName=value1headerName=value2)。

Header Merging/Overwriting

By default headers are merged. So for example if you do like this:
初期設定では指定された HTTP ヘッダーはマージするようになっています。
例えば、次のように記述した場合、HTTP リクエストには2つの HTTP ヘッダー(x: 1x: 2)が含まれることになります。

given().header("x", "1").header("x", "2"). ..

HTTP ヘッダーをマージするかどうかは HeaderConfig で変更できます。
この場合送信する HTTP ヘッダーとして送信するのは x: 2 です。

given().
        config(RestAssuredConfig.config().headerConfig(headerConfig().overwriteHeadersWithName("x"))).
        header("x", "1").
        header("x", "2").
when().
        get("/something").
...

4.5. Content Type

given().contentType(ContentType.TEXT). ..
given().contentType("application/json"). ..

4.6. Request Body

given().body("some body"). .. // Works for POST, PUT and DELETE requests
given().request().body("some body"). .. // More explicit (optional)
given().body(new byte[]{42}). .. // Works for POST, PUT and DELETE
given().request().body(new byte[]{42}). .. // More explicit (optional)

serialization では Java オブジェクトを JSON ドキュメントや XML ドキュメントへシリアライズする方法を説明しています。

5. Verifying Response Data

HTTP レスポンスについて検証できるのは、ステータスコードやステータスライン、HTTP Cookie、HTTP ヘッダー、コンテンツタイプ、レスポンス本文です。

5.1. Response Body

JSON ドキュメントXML ドキュメント の具体例を参照してください。

レスポンス本文を Java オブジェクトに写像することもできます。
詳しくは deserialization を参照してください。

5.2. Cookies

get("/x").then().assertThat().cookie("cookieName", "cookieValue"). ..
get("/x").then().assertThat().cookies("cookieName1", "cookieValue1", "cookieName2", "cookieValue2"). ..
get("/x").then().assertThat().cookies("cookieName1", "cookieValue1", "cookieName2", containsString("Value2")). ..

5.3. Status

get("/x").then().assertThat().statusCode(200). ..
get("/x").then().assertThat().statusLine("something"). ..
get("/x").then().assertThat().statusLine(containsString("some")). ..

5.4. Headers

get("/x").then().assertThat().header("headerName", "headerValue"). ..
get("/x").then().assertThat().headers("headerName1", "headerValue1", "headerName2", "headerValue2"). ..
get("/x").then().assertThat().headers("headerName1", "headerValue1", "headerName2", containsString("Value2")). ..

HTTP ヘッダーを検証するときは写像関数も利用できます。
例えば、Content-Length ヘッダーの値が 1000 未満であることを確認するなら、ヘッダーの値を int へ変換し、Integer として Hamcrest マッチャーに渡すようにできます。

get("/something").then().assertThat().header("Content-Length", Integer::parseInt, lessThan(1000));

5.5. Content-Type

get("/x").then().assertThat().contentType(ContentType.JSON). ..

5.6. Full body/content matching

get("/x").then().assertThat().body(equalTo("something")). ..

5.7. Use the response to verify other parts of the response

You can use data from the response to verify another part of the response. For example consider the following JSON document returned from service x:
レスポンスから取得したデータを、レスポンスの他の部分の検証に使うことができます。
例えばあるサービスが次のような JSON ドキュメントを返したことにしましょう。

{ "userId" : "some-id", "href" : "http://localhost:8080/some-id" }

このとき、"href" 属性の値が "userId" 属性の値で終端しているか確かめたいことにします。
そういうときは、io.restassured.matcher.ResponseAwareMatcher で次のように記述します。

get("/x").then().body("href", new ResponseAwareMatcher<Response>() {
                                  public Matcher<?> matcher(Response response) {
                                      return equalTo("http://localhost:8080/" + response.path("userId"));
                                  }
                              });

Java 8 を使っているなら代わりにラムダ式を使うことが出来ます。

get("/x").then().body("href", response -> equalTo("http://localhost:8080/" + response.path("userId")));

io.restassured.matcher.RestAssuredMatchers には定義済みのいろいろなマッチャーがあります。
Spring Mock MVC モジュールを使っているなら io.restassured.module.mockmvc.matcher.RestAssuredMockMvcMatchers を使いましょう。

get("/x").then().body("href", endsWithPath("userId"));

ResponseAwareMatchers のマッチャーメソッドは、他のマッチャーメソッドや Hamcrest のマッチャーメソッドと組み合わせることができます。

get("/x").then().body("href", and(startsWith("http:/localhost:8080/"), endsWithPath("userId")));

and メソッドは io.restassured.matcher.ResponseAwareMatcherComposer のクラスメソッドです。

5.8. Measuring Response Time

REST Assured 2.8.0 から応答時間を計測できるようになりました。

long timeInMs = get("/lotto").time()

時間単位を指定することもできます。

long timeInSeconds = get("/lotto").timeIn(SECONDS);

SECONDSTimeUnit の列挙値です。
応答時間の計測にバリデーション DSL を組み合わせることもできます。

when().
      get("/lotto").
then().
      time(lessThan(2000L)); // Milliseconds

時間単位も指定できます。

when().
      get("/lotto").
then().
      time(lessThan(2L), SECONDS);

応答時間の計測は JVM が十分に暖まっている状態で行うようにしてください(単発のテストで計測しても不正確な結果しか得られません)。
また、計測値はサーバーの処理時間を厳密に保証するものではありません(HTTP の往復時間や REST Assured の処理時間などを含むため)。

6. Authentication

REST Assured はさまざまな認証方式に対応しています。
具体的には OAuth、Digest認証、証明書、フォーム認証、プリエンプティブベーシック認証等です。
認証方式はそれぞれのリクエストに指定できます。

given().auth().basic("username", "password"). ..

全てのリクエストで使用する認証方式を指定することもできます。

RestAssured.authentication = basic("username", "password");

他にも、リクエストやレスポンスの仕様 として指定することができます。

6.1. Basic Authentication

ベーシック認証には2種類あります。
1つは「プリエンプティブベーシック認証」、もう1つは「チャレンジベーシック認証」です。

6.1.1. Preemptive Basic Authentication

余計な接続をする負担を減らすため、特定の時点でサーバーが 404(Unauthorized) レスポンスステータスを返す前に、資格情報を送信する方式です。
サーバーがチャレンジを処理する能力をテストする場合を除いて、ほとんどの場面で使われることになります。

given().auth().preemptive().basic("username", "password").when().get("/secured/hello").then().statusCode(200);

6.1.2. Challenged Basic Authentication

「チャレンジベーシック認証」を使う場合、サーバーが明示的に要求しない限り、REST Assured は資格情報を提供しません。
つまり、REST Assured は最初にチャレンジのためのリクエストを送信してから、資格情報を HTTP ヘッダーに設定したリクエストを送信するのです。

given().auth().basic("username", "password").when().get("/secured/hello").then().statusCode(200);

6.2. Digest Authentication

今のところ「チャレンジダイジェスト認証」にだけ対応しています。

given().auth().digest("username", "password").when().get("/secured"). ..

6.3. Form Authentication

フォーム認証 はインターネットで非常に広く使われている方式です。
ユーザーはWebページで資格情報(ユーザー名とパスワード)を入力し、ログインボタンで送信します。
フォーム認証のための必要最小限のWebページは次のようになるでしょう。

<html>
  <head>
    <title>Login</title>
  </head>

  <body>
    <form action="j_spring_security_check" method="POST">
      <table>
        <tr><td>User:&nbsp;</td><td><input type='text' name='j_username'></td></tr>
        <tr><td>Password:</td><td><input type='password' name='j_password'></td></tr>
          <tr><td colspan='2'><input name="submit" type="submit"/></td></tr>
       </table>
        </form>
      </body>
 </html>

サーバーは、ユーザーが "j_username" フィールドと "j_password" フィールトを入力して "submit" ボタンをクリックすることを期待しています。
フォーム認証で保護されたサービスを REST Assured でテストするには次のように記述します。

    given().
        .auth().form("John", "Doe")
    .when()
        .get("/formAuth")
    .then()
        .statusCode(200);

最適な動作をするわけではありません。
このように記述した場合、REST Assured はログインページを取得するための余計なリクエストを送信するからです。
REST Assured は取得したWebページを解析し、ユーザー名とパスワードに対応する入力フィールドと、フォームアクションURIを探索します。
Webページの複雑さによって解析に失敗する場合もあります。
フォーム認証を構成するときは、あらかじめ解析して得られるはずの情報を指定したほうがよいです。
例えば次のように記述します。

    given()
        .auth()
        .form("John", "Doe", new FormAuthConfig("/j_spring_security_check", "j_username", "j_password"))
    .when()
        .get("/formAuth")
    .then()
        .statusCode(200);

この場合 REST Assured はログインページを取得し、解析するためのリクエストを送信する必要がありません。
Spring Security が初期設定で構成されているなら、FormAuthConfig に定義済みの springSecurity を使うことができます。

    given()
        .auth().form("John", "Doe", FormAuthConfig.springSecurity())
    .when()
        .get("/formAuth")
    .then()
        .statusCode(200);

6.3.1. CSRF

サーバーのレスポンスに CSRF 対策のためのトークン値を含めるのが一般的になっています。
REST Assured はサーバーから受信した CSRF トークンを自動的に解釈するようになっていますが、そのためには 必ず Webページ(Webサイトの一部)を取得するリクエストを送信しなければなりません。

CSRF 機能は次のように有効化します。

    given()
        .auth().form("John", "Doe", formAuthConfig().withAutoDetectionOfCsrf())
    .when()
        .get("/formAuth")
    .then()
        .statusCode(200);

この場合、REST Assured は自動的にWebページを解析してCSRFトークンを探索します。
より正確にCSRFトークンを探索できるようにするため、REST Assured にフィールド名を指定することができます。
次のコード例は、Spring Security が初期設定で構成されているものとして、FormAuthConfig に定義済みの springSecurity を使用し、"\_csrf" で終わるフィールド名を CSRF トークンの設定されたフィールドとして探索させています。

    given()
        .auth().form("John", "Doe", springSecurity().withCsrfFieldName("_csrf"))
    .when()
        .get("/formAuth")
    .then()
        .statusCode(200);

初期設定では、CSFR トークンをフォームパラメータとして送信するようになっています。
ただし、必要に応じて HTTP ヘッダーとして送信するように設定することができます。

    given()
        .auth().form("John", "Doe", springSecurity().withCsrfFieldName("_csrf").sendCsrfTokenAsHeader())
    .when()
        .get("/formAuth")
    .then()
        .statusCode(200);

6.3.2. Include additional fields in Form Authentication

REST Assured 3.1.0 からフォーム認証へ入力フィールドを追加できるようになりました。
FormAuthConfig に追加するフィールドを指定するだけです。
例えば、次のようなWebページがあるとします。

<html>
<head>
   <title>Login</title>
</head>
<body>
<form action="/login" method="POST">
   <table>
       <tr>
           <td>User:&nbsp;</td>
           <td><input type="text" name="j_username"></td>
       </tr>
       <tr>
           <td>Password:</td>
           <td><input type="password" name="j_password"></td>
       </tr>
       <tr>
           <td colspan="2"><input name="submit" type="submit"/></td>
       </tr>
   </table>
   <input type="hidden" name="firstInputField" value="value1"/>
   <input type="hidden" name="secondInputField" value="value2"/>
</form>
</body>
</html>

そして、firstInputFieldsecondInputField を追加したいときは、次のように記述します。

given().auth().form("username", "password",
    formAuthConfig().withAdditionalFields("firstInputField", "secondInputField")). ..

REST Assured は自動的にWebページを解析し、指定したフィールドを探索し、発見した値をログインリクエストのフォームパラメータへ設定します。

6.4. OAuth

OAuth 1 や OAuth 2(クエリパラメータに署名する)を使用するには、クラスパスに ScribeJava を追加しなければなりません。
あなたのプロジェクトが Maven を使っているなら次のような依存ライブラリを追加します。
Maven を使っていない場合は GitHub のリリース から取得した jar ファイルをクラスパスに配置します。

<dependency>
            <groupId>com.github.scribejava</groupId>
            <artifactId>scribejava-apis</artifactId>
            <version>8.3.1</version>
            <scope>test</scope>
</dependency>

6.4.1. OAuth 1

OAuth 1 を使用するにはクラスパスに ScribeJava が必要です。
認証処理は次のように記述します。

given().auth().oauth(..). ..

6.4.2. OAuth 2

REST Assured 2.5.0 から、OAuth 2 を使用するときに ScribeJava へ依存しなくなりました。

given().auth().oauth2(accessToken). ..

このように記述すると、OAuth 2 の accessToken を HTTP ヘッダーに埋め込むことができます。
明示的に次のように記述することもできます。

given().auth().preemptive().oauth2(accessToken). ..

given().auth().oauth2(..) という記法は後方互換性のために残されています(やっている内容は同じです)。
OAuth 2 トークンをクエリパラメータで送信させたいときは、クラスパスに ScribeJava を配置して、次のように記述します。

given().auth().oauth2(accessToken, OAuthSignature.QUERY_STRING). ..

6.5. Custom Authentication

REST Assured では独自の認証プロバイダーを使用できます。
そのためには、io.restassured.spi.AuthFilter インターフェイスを実装したクラスを filter に指定します。
例えば、決して安全性を高める方法ではありませんが、あなたのサービスが独自の HTTP ヘッダー "AUTH" に、2種類の HTTP ヘッダーの値を組み合わせた値を要求するなら、次のように記述します。

    given()
        .filter((requestSpec, responseSpec, ctx) -> {
            String header1 = requestSpec.getHeaders().getValue("header1");
            String header2 = requestSpec.getHeaders().getValue("header2");
            requestSpec.header("AUTH", header1 + header2);
            return ctx.next(requestSpec, responseSpec);
        })
    .when()
        .get("/customAuth")
    .then()
        .statusCode(200);

Filter ではなく AuthFilter を使用するべき理由は、given().auth().none(). .. のように記述した場合、AuthFilters が自動的に除去してくれるからです。

7. Multi-part form data

巨大なデータをサーバーに送信するときは、マルチパート形式で送信するのが一般的です。
REST Assured では multiPart メソッドを使って、ファイルやバイト配列、入力ストリームや文字列を送信できます。
例えば、次のように記述すると簡単にファイルをアップロードできます。

    given()
        .multiPart(new File("/path/to/file"))
    when()
        .post("/upload");

このコード例では、マルチパート形式のデータ構造において、あるコンテンツに対応する部分の名前が "file" になります。
HTML では input タグの name 属性が使われます。
次のような HTML について考えてみましょう。

<form id="uploadForm" action="/upload" method="post" enctype="multipart/form-data">
        <input type="file" name="file" size="40">
        <input type=submit value="Upload!">
</form>

この場合、input タグの name 属性が "file" なので、あるコンテンツに対応する部分の名前は "file" になります。
別の名前にするときは次のように記述します。

    given()
        .multiPart("controlName", new File("/path/to/file"))
    .when()
        .post("/upload");

同じリクエストで複数のコンテンツを送信するときは次のように記述します。

byte[] someData = ..
given()
    .multiPart("controlName1", new File("/path/to/file"))
    .multiPart("controlName2", "my_file_name.txt", someData)
    .multiPart("controlName3", someJavaObject, "application/json")
.when()
    .post("/upload");

より複雑な制御が必要なときは MultiPartSpecBuilder を使います。

Greeting greeting = new Greeting();
greeting.setFirstName("John");
greeting.setLastName("Doe");

given()
    .multiPart(new MultiPartSpecBuilder(greeting, ObjectMapperType.JACKSON_2)
        .fileName("greeting.json")
        .controlName("text")
        .mimeType("application/vnd.custom+json").build())
.when()
    .post("/multipart/json")
.then()
    .statusCode(200);

特に、コンテンツに対応する名前の初期値やファイル名を変更したい場合は MultiPartConfig を構成します。

given().config(config().multiPartConfig(multiPartConfig().defaultControlName("something-else"))). ..

このコード例では、コンテンツに対応する名前が "file" ではなく "something-else" になります。

より詳しい内容は JayWay のブログ記事 を参照してください。

8. Object Mapping

REST Assured は Java オブジェクトと JSON および XML を相互変換できるようになっています。
JSON を処理するにはクラスパスに Jackson や Jackson2、Gson や Johnzon の jar ファイルを配置しなければなりません。
また、XML を処理するには JAXB が必要です。

8.1. Serialization

次のような Java オブジェクトを JSON にシリアライズして送信する方法がいろいろあります。

public class Message {
    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

8.1.1. Content-Type based Serialization

Message message = new Message();
message.setMessage("My messagee");
given()
    .contentType("application/json")
    .body(message)
.when()
    .post("/message");

このコード例では、リクエストに指定した HTTP ヘッダー content-type の値である "application/json" に従って、オブジェクトを JSON にシリアライズします。
最初はクラスパスから Jackson を探索し、無ければ Gson を使います。
content-type の値を "application/xml" にすると、JAXB を使用して XML へシリアライズします。
content-type を指定しなかった場合は、次の順にシリアライズを試みます。

  1. JSON using Jackson 2 (Faster Jackson (databind))

  2. JSON using Jackson (databind)

  3. JSON using Gson

  4. JSON using Johnzon

  5. JSON-B using Eclipse Yasson

  6. XML using JAXB

REST Assured は content-type に含まれる charset も考慮します。

Message message = new Message();
message.setMessage("My messagee");
given()
    .contentType("application/json; charset=UTF-16")
    .body(message)
.when()
    .post("/message");

Message クラスのインスタンスをフォームパラメータへシリアライズすることもできます。

Message message = new Message();
message.setMessage("My messagee");
given()
    .contentType("application/json; charset=UTF-16")
    .formParam("param1", message)
.when()
    .post("/message");

このコード例では、文字エンコーディングを UTF-16 として、Jackson (databind) あるいは Gson で JSON へシリアライズします。

8.1.2. Create JSON from a HashMap

Map のインスタンスから JSON ドキュメントを作成できます。

Map<String, Object>  jsonAsMap = new HashMap<>();
jsonAsMap.put("firstName", "John");
jsonAsMap.put("lastName", "Doe");

given()
    .contentType(JSON)
    .body(jsonAsMap)
.when()
    .post("/somewhere")
.then()
    .statusCode(200);

このコード例は、次のような JSON ドキュメントをリクエスト本文として送信します。

{ "firstName" : "John", "lastName" : "Doe" }

8.1.3. Using an Explicit Serializer

クラスパスに複数のオブジェクトマッピングライブラリが存在する場合や、content-type の値を無視させたい場合は、明示的にシリアライザーを指定します。

Message message = new Message();
message.setMessage("My messagee");
given()
   .body(message, ObjectMapperType.JAXB)
.when()
  .post("/message");

このコード例では message オブジェクトを JAXB で XML へシリアライズします。

8.2. Deserialization

レスポンス本文を、Java オブジェクトにデシリアライズする方法もいろいろあります。

public class Message {
    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

8.2.1. Content-Type based Deserialization

サーバーから次のような JSON ドキュメントを受信したことにします。

{"message":"My message"}

Message クラスのオブジェクトへデシリアライズするには次のように記述します。

Message message = get("/message").as(Message.class);

この場合、受信した HTTP ヘッダー content-type の値は "application/json" でなければなりません("json" を含む値ならなんでも構いません)。

一方、サーバーから次のような XML ドキュメントを受信したことにします。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<message>
      <message>My message</message>
</message>

この場合、受信した HTTP ヘッダー content-type の値は "application/xml" でなければなりません。
同じコードのままで動作します。

Message message = get("/message").as(Message.class);
Custom Content-Type Deserialization

サーバーから受信した content-type の値が "application/something" のように独自の値でも、いろいろな方法で Java オブジェクトへデシリアライズさせることができます。
具体的には、明示的に指定する方法や、独自の content-type に対応するパーサーを登録する方法があります。

content-type に対応するパーサーを登録するには次のように記述します。

Message message = expect().parser("application/something", Parser.XML).when().get("/message").as(Message.class);

既定のパーサーを登録するには次のように記述します。
既定のパーサーは、クラスメンバ変数 へ登録することもできますし、レスポンスの仕様 として登録することもできます。

Message message = expect().defaultParser(Parser.XML).when().get("/message").as(Message.class);

8.2.2. Using an Explicit Deserializer

クラスパスに複数のオブジェクトマッピングライブラリが存在する場合や、content-type の値を無視させたい場合は、明示的にデシリアライザーを指定します。

Message message = get("/message").as(Message.class, ObjectMapperType.GSON);

8.3. Configuration

既定のオブジェクトマッパーは ObjectMapperConfig で設定できます。
また、ObjectMapperConfig詳細設定 へ指定できます。
例えば、Gson のフィールド名規則を小文字とアンダースコアで構成するには次のように記述します。

RestAssured.config = RestAssuredConfig.config().objectMapperConfig(objectMapperConfig().gsonObjectMapperFactory(
                new GsonObjectMapperFactory() {
                    public Gson create(Class cls, String charset) {
                        return new GsonBuilder().setFieldNamingPolicy(LOWER_CASE_WITH_UNDERSCORES).create();
                    }
                }
        ));

REST Assured は Gson、JAXB、Jackson、Jackson2、Eclipse Yasson(JSON-B)のための定義済みファクトリクラスを提供しています。

8.4. Custom

REST Assured はクラスパスを探索して利用可能なオブジェクトマッパーを判断します。
未対応のオブジェクトマッパーを利用したい場合は、 io.restassured.mapper.ObjectMapper の独自実装を、body メソッドの第二引数へ指定します。

given().body(myJavaObject, myObjectMapper).when().post("..")

クラスメンバ変数へ設定すれば、全ての呼び出しから利用させることができます。

RestAssured.config = RestAssuredConfig.config().objectMapperConfig(new ObjectMapperConfig(myObjectMapper));

具体例は ソースコード で確認してください。

9. Parsers

9.1. Custom

REST Assured は HTML、XML、JSON の定義済みパーサーを提供します。
また、REST Assured が未対応の content-type に対応するパーサーを登録することもできます。

RestAssured.registerParser(<content-type>, <parser>);

MIMEタイプ "application/vnd.uoml+xml" を XML パーサーで解析させるときは次のように記述します。

RestAssured.registerParser("application/vnd.uoml+xml", Parser.XML);

登録したパーサーは解除できます。

RestAssured.unregisterParser("application/vnd.uoml+xml");

リクエストごとにパーサーを指定することもできます。

get(..).then().using().parser("application/vnd.uoml+xml", Parser.XML). ..;

レスポンスの仕様 として指定することもできます。

9.2. Default

レスポンスに HTTP ヘッダーの content-type が無い場合などのために、既定のパーサーを登録しておくと便利です。

RestAssured.defaultParser = Parser.JSON;

リクエストごとに既定のパーサーを指定することもできます。

get("/x").then().using().defaultParser(Parser.JSON). ..

レスポンスの仕様 として指定することもできます。

10. Default values

初期設定の REST Assured はリクエストを localhost の 8080 番ポートに送信します。
リクエストを送信するポート番号を変更したい場合は次のように記述します。

given().port(80). ..

単純にポート番号を含むURLを指定できます。

..when().get("http://myhost.org:80/doSomething");

全てのリクエストで使用する URI、パス、ポート番号、認証方式を変更できます。

RestAssured.baseURI = "http://myhost.org";
RestAssured.port = 80;
RestAssured.basePath = "/resource";
RestAssured.authentication = basic("username", "password");
RestAssured.rootPath = "x.y.z";

この場合、get("/hello") というコードは、"username" と "password" を資格情報とするベーシック認証で http://myhost.org:80/resource/hello に GET リクエストを送信します。
rootPath について詳しくは ルートパス を参照してください。

他にもいろいろな初期値を変更できます。

RestAssured.filters(..); // フィルターのリスト
RestAssured.requestSpecification = .. // リクエストの仕様
RestAssured.responseSpecification = .. // レスポンスの仕様
RestAssured.urlEncodingEnabled = .. // リクエストパラメータの URL エンコードの有効化
RestAssured.defaultParser = .. // 未対応の content-type に対するレスポンス本文のパーサー
RestAssured.registerParser(..) // content-type に対応するパーサー
RestAssured.unregisterParser(..) // content-type から除外するパーサー

reset メソッドは、それぞれの設定値を初期値に戻します(baseURI(localhost)、basePath(なし)、ポート番号(8080)、ルートパス(なし)、認証方式(なし)、URL エンコーディング(有効))。

RestAssured.reset();

11. Specification Re-use

いくつものテストで同じレスポンスの期待値やリクエストパラメータを重複させる代わりに、仕様として再利用できます。
リクエストの仕様は RequestSpecBuilder で、レスポンスの仕様は ResponseSpecBuilder で定義できます。

ステータスコードの期待値が 200、レスポンス本文の期待値が JSON 配列 x.y の要素数が2であることとするレスポンスの仕様は、次のように記述します。

ResponseSpecBuilder builder = new ResponseSpecBuilder();
builder.expectStatusCode(200);
builder.expectBody("x.y.size()", is(2));
ResponseSpecification responseSpec = builder.build();

// "responseSpec" は他のテストでも再利用できます
when()
   .get("/something")
.then()
   .spec(responseSpec)
   .body("x.y.z", equalTo("something"));

この例では、"responseSpec" として定義したレスポンス本文に関する期待値に、このテスト特有の期待値をマージすることになります。
全ての期待値を満たさなければテストは成功しません。

複数のテストで再利用するべきリクエストデータも同じように定義できます。

RequestSpecBuilder builder = new RequestSpecBuilder();
builder.addParam("parameter1", "parameterValue");
builder.addHeader("header1", "headerValue");
RequestSpecification requestSpec = builder.build();

given()
    .spec(requestSpec)
    .param("parameter2", "paramValue")
.when()
    .get("/something")
.then()
    .body("x.y.z", equalTo("something"));

この例でも "requestSpec" として定義した内容に、このテスト特有の内容をマージすることになります。
従って、このテストでは1つの HTTP ヘッダー "header1" と2つのリクエストパラメータ "parameter1" `"parameter2" を含むリクエストを送信することになります。

11.1. Querying RequestSpecification

RequestSpecification に定義した値を参照したり抽出したりできると役に立つ場合があります。
そういう場合は io.restassured.specification.SpecificationQuerier を使用します。

RequestSpecification spec = ...
QueryableRequestSpecification queryable = SpecificationQuerier.query(spec);
String headerValue = queryable.getHeaders().getValue("header");
String param = queryable.getFormParams().get("someparam");

12. Filters

フィルターを使うと、コミットする前のリクエストや、期待値と突き合わせて評価する前のリクエストを検証したり、変更したりできるようになります。
AOP(アスペクト指向プログラミング)における "around advice" のように考えることができます。
フィルターは、独自の認証方式やセッション管理、ログ出力を実現するためにも使用できます。
独自のフィルターを作成するときは io.restassured.filter.Filter を実装します。

given().filter(new MyFilter()). ..

REST Assured では次のようなフィルターを利用できるようになっています。

  1. io.restassured.filter.log.RequestLoggingFilter: リクエストの仕様について、詳細な内容を出力します

  2. io.restassured.filter.log.ResponseLoggingFilter: 指定されたステータスコードの一致するレスポンスについて、詳細な内容を出力します。

  3. io.restassured.filter.log.ErrorLoggingFilter: エラーレスポンスを受信した場合(ステータスコードが 400 以上 500 未満の場合)、レスポンスの詳細な内容を出力します

Ordered Filters

REST Assured 3.0.2 から、 io.restassured.filter.OrderedFilter を実装することで、フィルターの適用順序を制御できるようになりました。
getOrder メソッドの返す数値がフィルターの優先順位になります。
小さいほど優先順位が高くなります。
つまり、Integer.MIN_VALUE の優先順位は最高、Inteer.MAX_VALUE の優先順位は最低です。
OrderedFilter を実装していないフィルターの優先順位は getOrder メソッドが 1000 を返す場合と同じになります。

OrderedFilter の使い方を知りたければ サンプルコード を参照してください。

Response Builder

フィルターで レスポンスオブジェクト を変更するときは、 ResponseBuilder で元のレスポンスオブジェクトから新しいオブジェクトを作成しなければなりません。
例えば、レスポンス本文を "something" に変更したいときは次のように記述します。

Response newResponse = new ResponseBuilder().clone(originalResponse).setBody("Something").build();

13. Logging

リクエストやレスポンスの詳細な内容を出力することが、正しい期待値や正しいリクエストを作成するのに役立つ場合があります。
そういう場合は REST Assured に組み込みのフィルターを使えば簡単です。

13.1. Request Logging

REST Assured 1.5 から、 RequestLoggingFilter で実際にサーバーへ送信する前にリクエストの仕様をログに出力できるようになりました。
HTTP Builder や HTTP Client の追加した HTTP ヘッダーも出力するので注意してください。
ただし、このフィルターは基本的にリクエストの仕様に定義した内容 だけ を出力するようになっています。
実際にサーバーへ送信するリクエストの内容そのものではないということです。
また、RequestLoggingFilter より優先度の低いフィルターが変更した内容は出力できません。

サーバーに送信したリクエストと 完全に同じ内容 をログに出力したいときは、 HTTP Client のログ出力 を検討するか、 Wireshark などのツール利用を検討してください。

given().log().all(). .. // リクエストの仕様に定義したリクエストパラメータ、HTTP ヘッダー、リクエスト本文等、全てをログに出力します。
given().log().params(). .. // リクエストパラメータだけをログに出力します。
given().log().body(). .. // リクエスト本文だけをログに出力します。
given().log().headers(). .. // HTTP ヘッダーだけをログに出力します。
given().log().cookies(). .. // HTTP Cookie だけをログに出力します。
given().log().method(). .. // リクエストメソッドだけをログに出力します。
given().log().path(). .. // パスだけをログに出力します。

13.2. Response Logging

ステータスコードの値を無視してレスポンス本文をログに出力させたいときは次のように記述します。

get("/x").then().log().body() ..

このコード例では、たとえエラーレスポンスでもレスポンス本文をログに出力します。
エラーレスポンスの場合だけログに出力したい場合は次のように記述します。

get("/x").then().log().ifError(). ..

ステータスラインや HTTP ヘッダー、HTTP Cookie など全ての詳細な内容をログに出力したいときは次のように記述します。

get("/x").then().log().all(). ..

ステータスラインだけ、HTTP ヘッダーだけ、HTTP Cookie だけをログに出力したいときは次のように記述します。

get("/x").then().log().statusLine(). .. // ステータスラインだけをログに出力します。
get("/x").then().log().headers(). .. // HTTP ヘッダーだけをログに出力します。
get("/x").then().log().cookies(). .. // HTTP Cookie だけをログに出力します。

ステータスコードが指定した値に一致する、あるいは指定した条件と一致する場合だけログを出力したいときは次のように記述します。

get("/x").then().log().ifStatusCodeIsEqualTo(302). .. // ステータスコードが 302 のときだけログに出力します。
get("/x").then().log().ifStatusCodeMatches(matcher). .. // ステータスコードが Hamcrest マッチャーで真になったときだけログに出力します。

13.3. Log if validation fails

REST Assured 2.3.1 から、バリデーションに失敗した場合だけリクエストやレスポンスをログに出力できるようになりました。

リクエストをログに出力するときは次のように記述します。

given().log().ifValidationFails(). ..

レスポンスをログに出力するときは次のように記述します。

.. .then().log().ifValidationFails(). ..

リクエストとレスポンスのログ出力を同じように制御するには、 LogConfig を設定します。

given().config(RestAssured.config().logConfig(logConfig().enableLoggingOfRequestAndResponseIfValidationFails(HEADERS))). ..

このコード例では、バリデーションが失敗したとき、HTTP ヘッダーだけをログに出力します。

全てのテストについて、バリデーションが失敗したときリクエストとレスポンスをログに出力させるには、次のように記述します。

RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();

13.4. Blacklist Headers from Logging

REST Assured 4.2.0 から、リクエストやレスポンスをログに出力するとき、ログに出力させない HTTP ヘッダーの不許可リストを設定できるようになりました。
HTTP ヘッダーの値には、実際の値の代わりに [ BLACKLISTED ] を出力するようになります。
LogConfig で設定できます。

given().config(config().logConfig(logConfig().blacklistHeader("Accept"))). ..

この場合、レスポンスは次のようにログへ出力されます。

Request method:   GET
Request URI:    http://localhost:8080/something
Proxy:          <none>
Request params: <none>
Query params:   <none>
Form params:    <none>
Path params:    <none>
Headers:        Accept=[ BLACKLISTED ]
Cookies:        <none>
Multiparts:     <none>
Body:           <none>

14. Root path

ルートパスを指定して、レスポンス本文の期待値に記述するパスの重複を減らすことができます。

ルートパスを指定しない場合は次のように記述します。

when()
     .get("/something")
.then()
     .body("x.y.firstName", is(..))
     .body("x.y.lastName", is(..))
     .body("x.y.age", is(..))
     .body("x.y.gender", is(..));

ルートパスを指定すると次のように記述できます。

when()
    .get("/something")
.then()
     .root("x.y"). // "root" メソッドで指定します
     .body("firstName", is(..))
     .body("lastName", is(..))
     .body("age", is(..))
     .body("gender", is(..));

既定のルートパスを設定することもできます。

RestAssured.rootPath = "x.y";

既定のルートパスを延長できると、複雑なユースケースで役立つ場合があります。
ルートパスは appendRoot メソッドで追加できます。

when()
     .get("/jsonStore")
.then()
     .root("store.%s", withArgs("book"))
     .body("category.size()", equalTo(4))
     .appendRoot("%s.%s", withArgs("author", "size()"))
     .body(withNoArgs(), equalTo(4));

途中でルートパスを縮小することもできます。

when()
     .get("/jsonStore")
.then()
     .root("store.category")
     .body("size()", equalTo(4))
     .detachRoot("category")
     .body("size()", equalTo(1));

15. Path arguments

定義済みの変数を組み合わせてパスを構成しているときは、パス引数形式にしたほうが便利な場合があります。

String someSubPath = "else";
int index = 1;
get("/x").then().body("something.%s[%d]", withArgs(someSubPath, index), equalTo("some value")). ..

このコード例では、レスポンス本文の something.else[0] が "some value" と一致することを検証できます。

一部だけ異なる複雑な ルートパス の重複した記述を減らすために使うこともできます。

when()
   .get("/x")
.then()
   .root("filters.filterConfig[%d].filterConfigGroups.find { it.name == 'GroupName' }.includes")
   .body(withArgs(0), hasItem("first"))
   .body(withArgs(1), hasItem("second")).
       ..

パス引数の記法は Java の 書式付き出力 と同じです。

withArgs メソッドを使うには io.restassured.RestAssured クラスの static imoprt が必要です。

ルートパスに記述された全ての引数がそろっているなら、引数無しでレスポンス本文を検証できるようにしたほうが便利でしょう。
そういうときは withNoArgs メソッドを使います。

when()
     .get("/jsonStore")
.then()
     .root("store.%s", withArgs("book"))
     .body("category.size()", equalTo(4))
     .appendRoot("%s.%s", withArgs("author", "size()"))
     .body(withNoArgs(), equalTo(4));

16. Session support

REST Assured は単純なセッション管理機能を提供しています。
セッションIDを指定するDSLは次のように記述します。

given().sessionId("1234"). ..

次のように記述した場合と同じことをしています。

given().cookie("JSESSIONID", "1234"). ..

全てのリクエストに指定するセッションIDの初期値をクラスメンバ変数に設定できます。

RestAssured.sessionId = "1234";

初期設定では HTTP Cookie の JSESSIONID からセッションIDを取得します。
取得元は SessionConfig で変更できます。

RestAssured.config = RestAssured.config().sessionConfig(new SessionConfig().sessionIdName("phpsessionid"));

RequestSpecBuilder でセッションIDを定義して、他のテストで再利用することもできます。

RequestSpecBuilder spec = new RequestSpecBuilder().setSessionId("value1").build();

// 最初のリクエストで送信するセッションIDは "value1"
given().spec(spec). ..
// 二回目のリクエストで送信するセッションIDも "value1"
given().spec(spec). ..

もちろん、レスポンスオブジェクトからセッションIDを取得できます。

String sessionId = get("/something").sessionId();

16.1. Session Filter

REST Assured 2.0.0 から、 SessionFilter でセッションIDの取得と送信を自動化できるようになりました。

SessionFilter sessionFilter = new SessionFilter();

given()
    .auth().form("John", "Doe")
    .filter(sessionFilter)
.when()
    .get("/formAuth")
.then()
    .statusCode(200);


given()
    .filter(sessionFilter) // 直前のレスポンスから取得したセッションIDを再利用する
.when()
    .get("/x")
.then()
    .statusCode(200);

SessionFilter の取得したセッションIDは次のように参照できます。

String sessionId = sessionFilter.getSessionId();

17. SSL

HTTP Builder や HTTP Client の提供する素晴らしい機能のおかげで、ほとんどの場合何もしなくても SSL を利用できるようになっています。
それでも、通信に失敗する場合はあります。
サーバーが不正な証明書を使っている場合は SSLPeerUnverifiedException が発生します。
簡単な回避策は relaxedHTTPSValidation で HTTPS のバリデーションを緩和することです。

given().relaxedHTTPSValidation().when().get("https://some_server.com"). ..

全てのリクエストについて設定することもできます。

RestAssured.useRelaxedHTTPSValidation();

リクエストの仕様 で設定することもできます。

次のコード例では SSLContext のプロトコルとして SSL を使用しています。
relaxedHTTPSValidation のオーバーロードメソッドでは別のプロトコルを指定できるのです。

given().relaxedHTTPSValidation("TLS").when().get("https://some_server.com"). ..

自分で作成した Java キーストアファイルを使用するより詳細な設定もできるようになっています。
それほど難しいことではありませんが、 HTTP Builder の SSL に関する説明 を読んでおくといいでしょう。

given().keystore("/pathToJksInClassPath", <password>). ..

全てのリクエストについて設定することもできます。

RestAssured.keystore("/pathToJksInClassPath", <password>);

リクエストの仕様 で設定することもできます。

パスワード付きのキーストアを読み込んでからトラストストアへ設定することもできます。

RestAssured.trustStore(keystore);

使い方は サンプルコード を参照してください。

より高度な SSL の設定をするときは SSL の設定 を参照してください。

17.1. SSL invalid hostname

REST Assured 2.2.0 から、サーバー証明書のホスト名とアクセスするホスト名が一致しない場合でも、Java キーストアファイルを作成、インポートしなくてもよくなりました。

全てのリクエストについて設定するときは次のように記述します。

RestAssured.config = RestAssured.config().sslConfig(sslConfig().allowAllHostnames());

単独のリクエストについて設定するときは次のように記述します。

given().config(RestAssured.config().sslConfig(sslConfig().allowAllHostnames())). .. ;

relaxedHTTPSValidation を有効化した場合、allowAllHostnames も有効になっているので注意してください。

18. URL Encoding

REST Assured は自動的に URL エンコード処理をするので、基本的には考慮する必要がありません。
URL エンコード処理を無効にするときはそのための設定が必要です。
具体的には、URL エンコードされている値を REST Assured のパラメータとして渡す場合があるでしょう。
URL エンコードを二重に適用しないよう、REST Assured の URL エンコード処理を無効にしなければならないのです。

String response = given()
    .urlEncodingEnabled(false)
    .get("https://jira.atlassian.com:443/rest/api/2.0.alpha1/search?jql=project%20=%20BAM%20AND%20issuetype%20=%20Bug")
    .asString();
..

全てのリクエストについて設定するときは次のように記述します。

RestAssured.baseURI = "https://jira.atlassian.com";
RestAssured.port = 443;
RestAssured.urlEncodingEnabled = false;
final String query = "project%20=%20BAM%20AND%20issuetype%20=%20Bug";
String response = get("/rest/api/2.0.alpha1/search?jql={q}", query);
..

19. Proxy Configuration

REST Assured 2.3.2 ではプロキシ対応機能を改善しました。

localhost の 8888 番ポートを指定するときは次のように記述します。

given().proxy("localhost", 8888). ..

プロキシホストが localhost の場合はポート番号を指定するだけでも動作します。

given().proxy(8888). .. // Will assume localhost

HTTPS でアクセスする必要があるときは、3番目の引数にプロトコルスキーマを指定するか、io.restassured.specification.ProxySpecification を使用します。

given().proxy(host("localhost").withScheme("https")). ..

host メソッドは io.restassured.specification.ProxySpecification のクラスメソッドです。

REST Assured 2.7.0 から、プリエンプティブベーシック認証でプロキシに接続できるようになりました。

given().proxy(auth("username", "password")).when() ..

auth メソッドは io.restassured.specification.ProxySpecification のクラスメソッドです。

host メソッドで別のホスト名を指定できます。

given().proxy(host("http://myhost.org").withAuth("username", "password")). ..

19.1. Static Proxy Configuration

全てのリクエストについて設定するときは次のように記述します。

RestAssured.proxy("localhost", 8888);

次のように記述することもできます。

RestAssured.proxy = host("localhost").withPort(8888);

19.2. Request Specification Proxy Configuration

リクエストの仕様へプロキシ接続を設定することもできます。

RequestSpecification specification = new RequestSpecBuilder().setProxy("localhost").build();
given().spec(specification). ..

20. Detailed configuration

RestAssuredConfig で次のような内容を設定できます。

単独のリクエストには次のように設定します。

given().config(RestAssured.config().redirect(redirectConfig().followRedirects(false))). ..

RequestSpecBuilder には次のように設定します。

RequestSpecification spec = new RequestSpecBuilder().setConfig(
    RestAssured.config().redirect(
        redirectConfig().followRedirects(false)))
.build();

全てのリクエストを対象とするには次のように設定します。

RestAssured.config = config().redirect(
    redirectConfig().followRedirects(true).and().maxRedirects(0));

config メソッドや newConfig メソッドは io.restassured.config.RestAssuredConfig のクラスメソッドです。

20.1. Encoder Config

EncoderConfig では、コンテンツとクエリパラメータで使用する文字エンコーディングと文字セットを指定できます(指定しなかった場合は HTTP ヘッダー content-type の値に従います)。
コンテンツの文字セットを指定しなかった場合、ISO-8859-1 になります。
クエリパラメータの文字セットを指定しなかった場合、UTF-8 になります。

RestAssured.config = RestAssured.config().encoderConfig(
    encoderConfig().defaultContentCharset("US-ASCII"));

EncoderConfigdefaultCharsetForContentType メソッドを使うと、content-type に文字セットが指定されていなかった場合に使用する文字セットのエンコーダを、content-type ごとに定義できます。

RestAssured.config = RestAssured.config(
    config().encoderConfig(
        encoderConfig().defaultCharsetForContentType("UTF-16", "application/xml")));

このコード例では、content-type の "application/xml" へ文字セットが明示的に指定されなかった場合、UTF-16 として扱います。
なお、"application/json" の既定の文字セットは RFC4627 で定義されており、UTF-8 として扱います。

20.1.1. Avoid adding the charset to content-type header automatically

REST Assured は自動的に文字セットのための HTTP ヘッダーを自動的に追加します。
この振る舞いを無効化するには EditorConfig で設定します。

RestAssured.config = RestAssured.config(
    config().encoderConfig(
        encoderConfig().appendDefaultContentCharsetToContentTypeIfUndefined(false)));

20.2. Decoder Config

DecoderConfig では全てのレスポンスについて、コンテンツをデコードするときの既定の文字セットを設定できます。
既定の文字セットである ISO-8859-1 以外の文字セットを想定している場合や、レスポンスの content-type で文字セットが指定されていなかった場合に役立ちます。

RestAssured.config = RestAssured.config().decoderConfig(
    decoderConfig().defaultContentCharset("UTF-8"));

特定のデコーダを指定することもできます。
この設定をすると、リクエストの HTTP ヘッダーに Accept-Encoding を自動的に追加し、レスポンス本文も自動的にデコードします。
組み込みのデコーダとして GZIPDEFLATE が利用できるようになっています。

GZIP の代わりに DEFLATE を使用する場合は次のように記述します。

given().config(RestAssured.config().decoderConfig(
    decoderConfig().contentDecoders(DEFLATE))). ..

DecoderConfigdefaultCharsetForContentType メソッドを使うと、content-type に文字セットが指定されていなかった場合に使用する文字セットのデコーダーを、content-type ごとに定義できます。

RestAssured.config = RestAssured.config(
    config().decoderConfig(
        decoderConfig().defaultCharsetForContentType("UTF-16", "application/xml")));

このコード例では、content-type の "application/xml" へ文字セットが明示的に指定されなかった場合、UTF-16 として扱います。
なお、"application/json" の既定の文字セットは RFC4627 で定義されており、UTF-8 として扱います。

20.3. Session Config

SessionConfig はセッションIDの受け渡しに使う既定のパラメータ名を設定できます。
初期値は JSESSIONID です。
違う名前を使用するアプリケーションで セッション管理機能 を使いたい場合は設定しなければなりません。

RestAssured.config = RestAssured.config().sessionConfig(
    new SessionConfig().sessionIdName("phpsessionid"));

20.4. Redirect DSL

リダイレクトの振る舞いは DSL で設定できます。

given().redirects().max(12).and().redirects().follow(true).when(). ..

20.5. Connection Config

REST Assured は HTTP 接続のための設定を変更できます。
例えば、Apache HTTP Client でレスポンスを受信するたびに強制的に HTTP 接続を閉じるようにできます。
小さいレスポンスを返すリクエストを、大量に、高速に、連続して送信したい場合などが該当します。
もちろん、いくつかの塊として(巨大な)データを受信しているときは、レスポンスを受信してすぐに HTTP 接続を閉じてはいけません。
初期設定ではレスポンスを受信するたびに HTTP 接続を閉じない ようになっています。

RestAssured.config = RestAssured.config().connectionConfig(c
    onnectionConfig().closeIdleConnectionsAfterEachResponse());

20.6. Json Config

JsonPathConfig は REST Assured だけでなく、 JsonPath を単独で使用する場合の設定を変更できます。

次のコード例では JSON number の扱いを変更しています。

RestAssured.config = RestAssured.config().jsonConfig(
    jsonConfig().numberReturnType(NumberReturnType.BIG_DECIMAL))

20.7. HTTP Client Config

REST Assured が HTTP リクエストを送信するために使用している HTTP Client インスタンスの設定を変更できます。
初期設定では given メソッドが毎回新しいインスタンスを作成するようになっています。

作成したインスタンスを再利用できるようにするときは次のように記述します。

RestAssured.config = RestAssured.config().httpClient(
    httpClientConfig().reuseHttpClientInstance());

httpClientFactory メソッドで独自の HTTP Client インスタンスを指定することができます。

RestAssured.config = RestAssured.config().httpClient(
    httpClientConfig().httpClientFactory(
         new HttpClientConfig.HttpClientFactory() {

            @Override
            public HttpClient createHttpClient() {
                return new SystemDefaultHttpClient();
            }
        }));

注意:今は AbstractHttpClient のインスタンスしか指定できません。

もちろん、HTTP Client インスタンスの初期値を設定することもできます。

20.8. SSL Config

SSLConfig は、キーストアの種類やトラストストア、ホスト名検証器等、SSL の細かい設定を変更できます。

RestAssured.config = RestAssured.config().sslConfig(
    sslConfig()
    .with()
        .keystoreType(<type>)
    .and()
        .strictHostnames());

20.9. Param Config

ParamConfig はパラメータの種類ごとに、パラメータ名が衝突した場合の処理を変更できます。
初期設定では全ての値をマージするようになっています。

次のコード例では、REST Assured の送信するクエリ文字列は param1=value1&param1=value2 になります。

given().queryParam("param1", "value1").queryParam("param1", "value2").when().get("/x"). ...

後に指定した値で同じ名前のパラメータを 上書き したい場合は次のように記述します。

given()
    .config(config().paramConfig(paramConfig().queryParamsUpdateStrategy(REPLACE)))
    .queryParam("param1", "value1")
    .queryParam("param1", "value2")
.when()
    .get("/x"). ..

この場合、REST Assured は全てのパラメータをマージする代わりに、 param1 の値を value2 に上書きします(最後に指定した値です)。

パラメータの種類に応じて個別に設定するのではなく、全てのパラメータ種類で同じ処理をさせたいときは次のように記述します。

given().config(config().paramConfig(
    paramConfig().replaceAllParameters())). ..

この機能は Spring Mock Mvc モジュール でも対応しています。
ただし、ParamConfig の代わりに MockMvcParamConfig を使用します。

20.10. Failure Config

REST Assured 3.3.0 からは、バリデーションが失敗した場合に実行するコールバック処理を FailureConfig で指定できるようになりました。
リクエストやレスポンス、あるいはそれぞれの仕様に、独自のログ出力やデータ保存処理を追加するのに役立ちます。

例として、次のテストを実行してステータスコードが 200 じゃなかったら電子メールで通知させてみましょう。

given()
    .param("x", "y")
.when()
    .get("/hello")
.then()
    statusCode(200);

ResponseValidationFailureListener を実装して FailureConfig に指定します。

ResponseValidationFailureListener emailOnFailure = (reqSpec, respSpec, resp) -> emailService.sendEmail(
    "email@gmail.com", "Important test failed! Status code was: " + resp.statusCode());

given()
    .config(RestAssured.config().failureConfig(
        failureConfig().with().failureListeners(emailOnFailure)))
    .param("x", "y")
.when()
    .get("/hello")
.then()
    statusCode(200);

21. Spring Support

Spring MVC のコントローラを REST Assured の API でテストするため、2種類のモジュールを提供しています。

21.1. Spring Mock Mvc Module

REST Assured 2.2.0 から Spring Mock Mvc に対応する spring-mock-mvc モジュールが使用できるようになりました。
つまり、Spring MVC のコントローラのユニットテストができるようになったのです。

@Controller
public class GreetingController {

    private static final String template = "Hello, %s!";
    private final AtomicLong counter = new AtomicLong();

    @RequestMapping(value = "/greeting", method = GET)
    public @ResponseBody Greeting greeting(
            @RequestParam(value="name", required=false, defaultValue="World") String name) {
        return new Greeting(counter.incrementAndGet(), String.format(template, name));
    }
}

テストは RestAssuredMockMvc で記述します。

given()
    .standaloneSetup(new GreetingController())
    .param("name", "Johan")
.when()
    .get("/greeting")
.then()
    .statusCode(200)
    .body("id", equalTo(1))
    .body("content", equalTo("Hello, Johan!"));

REST Assured の基本的な記法そのままです。
すごい短い時間でテストを実行できるだけでなく、基本的な REST Assured に比べて、環境の準備や、(必要なら)モックを使用するのが簡単になっています。
基本的な REST Assured の準備に必要なことのほとんど(各種設定や仕様の準備、ロギング等)を RestAssuredMockMvc がやってくれるからです。

Maven プロジェクトなら次のような依存ライブラリを追加します。
そうでなければ jarファイル をダウンロードしてクラスパスに配置します。

<dependency>
      <groupId>io.rest-assured</groupId>
      <artifactId>spring-mock-mvc</artifactId>
      <version>4.4.0</version>
      <scope>test</scope>
</dependency>

21.1.1. Bootstrapping RestAssuredMockMvc

次のような import 文を追加するだけです。

io.restassured.module.mockmvc.RestAssuredMockMvc.*
io.restassured.module.mockmvc.matcher.RestAssuredMockMvcMatchers.*

元の import 文は削除します。

io.restassured.RestAssured.*
io.restassured.matcher.RestAssuredMatchers.*

他に必要な import 文があるなら static import のセクションを参照してください。

RestAssuredMockMvc のテストを実行するときは、先にコントローラや MockMvcWebApplicationContext を初期化しておかなければなりません。
前のコード例で見たように、リクエストごとにもろもろの準備を実行できます。

given().standaloneSetup(new GreetingController()). ..

クラスメソッドで実行することもできます。

RestAssuredMockMvc.standaloneSetup(new GreetingController());

クラスメソッドで実行する場合、REST Assured の DSL でコントローラや MockMvcWebApplicationContext のインスタンスを指定する必要はありません。
その場合、最初のコード例は次のように記述できます。

given()
    .param("name", "Johan")
.when()
    .get("/greeting")
.then()
    .statusCode(200)
    .body("id", equalTo(1))
    .body("content", equalTo("Hello, Johan!"));

21.1.2. Asynchronous Requests

RestAssuredRestAssuredMockMvc は 2.5.0 からリクエストを非同期で送信できるようになりました。

@Controller
public class PostAsyncController {

    @RequestMapping(value = "/stringBody", method = POST)
    public @ResponseBody
    Callable<String> stringBody(final @RequestBody String body) {
        return new Callable<String>() {
            public String call() throws Exception {
                return body;
            }
        };
    }
}

テストコードは次のように記述できます。

given()
    .body("a string")
.when()
    .async().post("/stringBody")
.then()
    .body(equalTo("a string"));

これらのコードのタイムアウト時間は初期値の1秒になっています。
タイムアウト時間は DSL で指定できます。

given()
    .body("a string")
.when()
    .async().with().timeout(20, TimeUnit.SECONDS).post("/stringBody")
.then()
    .body(equalTo("a string"));

AsyncConfig でもタイムアウト時間の初期値を設定できます。

given()
    .config(config().asyncConfig(withTimeout(100, TimeUnit.MILLISECONDS)))
    .body("a string")
.when()
    .async().post("/stringBody")
.then()
    .body(equalTo("a string"));

withTimeout メソッドは io.restassured.module.spring.commons.config.AsyncConfig のクラスメソッドで、タイムアウト時間を設定しただけの AsyncConfig を生成します。

全てのリクエストでタイムアウト時間を変更する場合は次のように記述します。
リクエスト1とリクエスト2のどちらでも、タイムアウト時間は100ミリ秒になります。

RestAssuredMockMvc.config = RestAssuredMockMvc.config().asyncConfig(
    withTimeout(100, TimeUnit.MILLISECONDS));

// リクエスト1
given()
    .body("a string")
.when()
    .async().post("/stringBody")
.then()
    .body(equalTo("a string"));

// リクエスト2
given()
    .body("another string")
.when()
    .async().post("/stringBody")
.then()
    .body(equalTo("a string"));

21.1.3. Adding Request Post Processors

Spring MockMvc は Request Post Processors を使用できますが、RestAssuredMockMvc でも使用できます。

given().postProcessors(myPostProcessor1, myPostProcessor2). ..

可読性を高めるためにも、RequestPostProcessorsorg.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors を指定する代わりに、auth メソッドを使うようにしたほうがいいでしょう。
同じ振る舞いになるはずです。

given().auth().with(httpBasic("username", "password")). ..

httpBasic メソッドは SecurityMockMvcRequestPostProcessor のクラスメソッドです。

21.1.4. Adding Result Handlers

Spring MockMvc は Result Handlers を使用できますが、RestAssuredMockMvc でも使用できます。

MockMvc の提供するログ出力機能を使用するときは次のように記述します。

.. .then().apply(print()). ..

print メソッドは org.springframework.test.web.servlet.result.MockMvcResultHandlers のクラスメソッドです。

REST Assured 2.6.0 より前のバージョンを使っている場合は代わりに resultHandlers メソッドを使うようにしてください(resultHandlers メソッドは 2.8.0 から非推奨になりました)。

given().resultHandlers(print()). ..

21.1.5. Using Result Matchers

Spring MockMvc は Result Matchers のさまざまな実装を提供しています。
中には役に立つものもあるでしょう。
RestAssuredMockMvc でも同じように使用できます。

例えば、何らかの理由でステータスコードが 200 に一致するかどうか ResultMatcher で判定しなければならないとしたら、次のように記述できます。

given()
    .param("name", "Johan")
.when()
    .get("/greeting")
.then()
    .assertThat(status().isOk())
    .body("id", equalTo(1))
    .body("content", equalTo("Hello, Johan!"));

status メソッドは org.springframework.test.web.servlet.result.MockMvcResultMatchers のクラスメソッドです。
assertThat メソッドの代わりに expect メソッドを使えるので、そのほうが素の MockMvc の記法に近づくでしょう。

21.1.6. Interceptors

MockHttpServletRequestBuilder を使えば実際に送信する前にリクエストの内容を変更できます。
そのためには、 MockHttpServletRequestBuilderInterceptor を実装して RestAssuredMockMvc に指定します。

given().interceptor(myInterceptor). ..

21.1.7. Spring Mock Mvc Specifications

通常の REST Assured のようにリクエストやレスポンスの仕様を定義して再利用性を高めることができます。
RestAssuredMockMvc では MockMvcRequestSpecBuilder でリクエストの仕様を作成しますが、レスポンスの仕様は ResponseSpecBuilder で作成します。

全てのリクエストやレスポンスで使用する仕様はクラスメンバ変数で変更できます。

RestAssuredMockMvc.requestSpecification = new MockMvcRequestSpecBuilder()
    .addQueryParam("name", "Johan")
    .build();
RestAssuredMockMvc.responseSpecification = new ResponseSpecBuilder()
    .expectStatusCode(200)
    .expectBody("content", equalTo("Hello, Johan!"))
    .build();

given()
    .standaloneSetup(new GreetingController())
.when()
    .get("/greeting")
.then()
    .body("id", equalTo(1));

21.1.8. Resetting RestAssuredMockMvc

reset メソッドで RestAssuredMockMvc の初期設定を復元できます。

21.2. Spring MVC Authentication

spring-mock-mvc モジュールは 2.3.0 から認証機能に対応しました。

given().auth().principal(..). ..

一部の認証方式を使用するには Spring Security ライブラリをクラスパスに配置しなければなりません(任意です)。
認証方式はクラスメンバ変数で変更できます。

RestAssuredMockMvc.authentication = principal("username", "password");

principal メソッドは RestAssuredMockMvc のクラスメソッドです。
リクエストビルダーで認証方式を変更することもできます。

MockMvcRequestSpecification spec = new MockMvcRequestSpecBuilder
    .setAuth(principal("username", "password"))
    .build();

21.2.1. Using Spring Security Test

spring-mock-mvc モジュールは 2.5.0 で Spring Security の対応を改善しました。
クラスパスに spring-security-test ライブラリがあるときは次のように記述できるようになります。

given().auth().with(httpBasic("username", "password")). ..

httpBasic メソッドは SecurityMockMvcRequestPostProcessor のクラスメソッドです。
このメソッドはベーシック認証ができるようにします。

この機能を有効にするには MockMvc のインスタンスに SecurityMockMvcConfigurer を指定しなければなりません。
直接指定する場合は次のように記述します。

MockMvc mvc = MockMvcBuilders
    .webAppContextSetup(context)
    .apply(SecurityMockMvcConfigurers.springSecurity())
    .build();

RestAssuredMockMvcAbstractMockMvcBuilder のインスタンスを指定した場合、自動的に springSecurity を構成します。

given()
    .webAppContextSetup(context)
    .auth().with(httpBasic("username", "password")). ..

完全なコード例は次のとおりです。

import io.restassured.module.mockmvc.RestAssuredMockMvc;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.context.WebApplicationContext;

import static io.restassured.module.mockmvc.RestAssuredMockMvc.given;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = MyConfiguration.class)
@WebAppConfiguration
public class BasicAuthExample {

    @Autowired
    private WebApplicationContext context;

    @Before public void
    rest_assured_is_initialized_with_the_web_application_context_before_each_test() {
        RestAssuredMockMvc.webAppContextSetup(context);
    }

    @After public void
    rest_assured_is_reset_after_each_test() {
        RestAssuredMockMvc.reset();
    }

    @Test public void
    basic_auth_example() {
        given().
                auth().with(httpBasic("username", "password")).
        when().
                get("/secured/x").
        then().
                statusCode(200).
                expect(authenticated().withUsername("username"));
    }
}

全てのリクエストで使用する認証方式はクラスメンバで変更できます。

RestAssuredMockMvc.authentication = with(httpBasic("username", "password"));

with メソッドは io.restassured.module.mockmvc.RestAssuredMockMvc のクラスメソッドです。
リクエストの仕様で指定することもできます。

21.2.2. Injecting a User

Spring Security Test ライブラリの提供する @WithMockUser@WithUserDetails といったアノテーションを使用できます。

@Controller
public class UserAwareController {

    @RequestMapping(value = "/user-aware", method = GET)
    public
    @ResponseBody
    String userAware(@AuthenticationPrincipal User user) {
        if (user == null || !user.getUsername().equals("authorized_user")) {
            throw new IllegalArgumentException("Not authorized");
        }

        return "Success";
    }
}

userAware メソッドの引数 User には @AuthenticationPrincipal が指定されているため、Spring Security がユーザーオブジェクトを注入します。
次のように記述すると、テスト用のユーザーを生成できます。

@WithMockUser(username = "authorized_user")
@Test public void
spring_security_mock_annotations_example() {
    given()
        .webAppContextSetup(context)
    .when()
        .get("/user-aware")
    .then()
        .statusCode(200)
        .body(equalTo("Success"))
        .expect(authenticated().withUsername("authorized_user"));
}

21.2.3. Spring Web Test Client Module

REST Assured 3.2.0 では Spring Reactive Web のテストに使用するコンポーネントとして spring-web-test-client モジュールを導入しました。
このモジュールを使用すると Spring WebFlux のコントローラのユニットテストを作成できるようになります。

次のような DTO クラスを JSON ドキュメントとして返すコントローラがあることにしましょう。

public class Greeting {

    private final long id;
    private final String content;

    public Greeting(long id, String content) {
        this.id = id;
        this.content = content;
    }

    public long getId() {
        return id;
    }

    public String getContent() {
        return content;
    }
}
@RestController
public class GreetingController {

    private static final String template = "Hello, %s!";
    private final AtomicLong counter = new AtomicLong();

    @GetMapping(value = "/greeting", produces = "application/json")
    public Mono<Greeting> greeting(@RequestParam(value="name") String name) {
        return Mono.just(new Greeting(counter.incrementAndGet(), String.format(template, name)));
    }
}

RestAssuredWebTestClient を使うと次のように記述できます。

package io.restassured.module.webtestclient;

import io.restassured.module.webtestclient.setup.GreetingController;
import org.junit.Test;
import static io.restassured.module.webtestclient.RestAssuredWebTestClient.given;

public class GreetingControllerTest {

    @Test
    public void greeting_controller_returns_json_greeting() {
        given()
            .standaloneSetup(new GreetingController())
            .param("name", "Johan")
        .when()
            .get("/greeting")
        .then()
            .statusCode(200)
            .body("id", equalTo(1))
            .body("content", equalTo("Hello, Johan!"));
    }
}

REST Assured の基本的な記法そのままです。
すごい短い時間でテストを実行できるだけでなく、基本的な REST Assured に比べて、環境の準備や、(必要なら)モックを使用するのが簡単になっています。
基本的な REST Assured の準備に必要なことのほとんど(各種設定や仕様の準備、ロギング等)を RestAssuredWebTestClient がやってくれるからです。

Maven プロジェクトなら spring-web-test-client モジュールを依存ライブラリに追加します。
そうでなければ jarファイル をダウンロードしてクラスパスに配置します。

<dependency>
      <groupId>io.rest-assured</groupId>
      <artifactId>spring-web-test-client</artifactId>
      <version>4.4.0</version>
      <scope>test</scope>
</dependency>

21.2.4. Bootstrapping RestAssuredWebTestClient

次のような import 文を追加するだけです。

io.restassured.module.webtestclient.RestAssuredWebTestClient.*
io.restassured.module.webtestclient.matcher.RestAssuredWebTestClientMatchers.*

元の import 文は削除します。

io.restassured.RestAssured.*
io.restassured.matcher.RestAssuredMatchers.*

他に必要な import 文があるなら static import のセクションを参照してください。

RestAssuredWebTestClient のテストを実行するときは、先にコントローラや WebTestClientWebApplicationContext を初期化しておかなければなりません。
前のコード例で見たように、リクエストごとにもろもろの準備を実行できます。

given().standaloneSetup(new GreetingController()). ..

クラスメソッドで実行することもできます。

RestAssuredWebTestClient.standaloneSetup(new GreetingController());

クラスメソッドで実行する場合、REST Assured の DSL でコントローラのインスタンスを指定する必要はありません。
その場合、最初のコード例は次のように記述できます。

given()
    .param("name", "Johan")
.when()
    .get("/greeting")
.then()
    .statusCode(200)
    .body("id", equalTo(1))
    .body("content", equalTo("Hello, Johan!"));

21.2.5. Spring Web Test Client Specifications

通常の REST Assured のようにリクエストやレスポンスの仕様を定義して再利用性を高めることができます。
RestAssuredWebTestClient では WebTestClientRequestSpecBuilder でリクエストの仕様を作成しますが、レスポンスの仕様は ResponseSpecBuilder で作成します。

全てのリクエストやレスポンスで使用する仕様はクラスメンバ変数で変更できます。

RestAssuredWebTestClient.requestSpecification = new WebTestClientRequestSpecBuilder()
    .addQueryParam("name", "Johan")
    .build();
RestAssuredWebTestClient.responseSpecification = new ResponseSpecBuilder()
    .expectStatusCode(200)
    .expectBody("content", equalTo("Hello, Johan!"))
    .build();

given()
    .standaloneSetup(new GreetingController())
.when()
    .get("/greeting")
.then()
    .body("id", equalTo(1));

21.2.6. Resetting RestAssuredWebTestClient

reset メソッドで RestAssuredWebTestClient の初期設定を復元できます。

21.3. Common Spring Module Documentation

21.3.1. Note on parameters

RestAssuredMockMvcRestAssuredWebTestClient はどちらも使用できるパラメータは同じで、paramformParamqueryParamMockMvc へ委譲するだけです。
通常の REST Assured と同様に、formParam でパラメータを指定すると、自動的に HTTP ヘッダーの content-type へ application/x-www-form-urlencoded を設定します。

22. Scala Support Module

REST Assured 2.6.0 で導入された scala-support モジュールは、 ResponseMockMvcResponse の "then" メソッドに、別名の "Then" メソッドを追加します。
Scala では then が予約語になっているため、Scala コンパイラが警告メッセージを出力するからです。
Then メソッドを使用するには scala-support モジュールの io.restassured.module.scala.RestAssuredSupport.AddThenToResponse を import 文に追加します。

import io.restassured.RestAssured.when
import io.restassured.module.scala.RestAssuredSupport.AddThenToResponse
import org.hamcrest.Matchers.equalTo
import org.junit.Test

@Test
def `trying out rest assured in scala with implicit conversion`() {
  when().
    get("/greetJSON").
  Then().
    statusCode(200).
    body("key", equalTo("value"))
}

spring-mock-mvc モジュール を使用する場合も同じようにします。

scala-support モジュールを依存ライブラリに追加するには次のように記述します。

SBT:
libraryDependencies += "io.rest-assured" % "scala-support" % "4.4.0"
Maven:
<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>scala-support</artifactId>
    <version>4.4.0</version>
    <scope>test</scope>
</dependency>
Gradle:
testImplementation 'io.rest-assured:scala-support:4.4.0'

No build manager:

クラスパスに jar ファイル を配置してください。

23. Kotlin

23.1. Avoid Escaping "when" Keyword

JetBrains の開発している Kotlin 言語はとても簡単に Java と統合できるので、REST Assured も簡単に利用できます。
ただし、1つだけ注意点があります。
Kotlin では when が予約語になっているため、メソッド名をエスケープしなければならないのです。

@Test
fun `kotlin rest assured example`() {
    given().
        param("firstName", "Johan").
        param("lastName", "Haleby").
    `when`().
        get("/greeting").
    then().
        statusCode(200).
        body("greeting.firstName", equalTo("Johan")).
        body("greeting.lastName", equalTo("Haleby"))
}

Kotlin Extension Module を使用すれば、簡単に 拡張メソッド を作成できるので、こちらの方がおすすめです。

例えば、when メソッドの別名 When メソッドを定義するには次のように記述します。

fun RequestSpecification.When(): RequestSpecification {
    return this.`when`()
}

そうすると、前のコードは次のように記述できます。

@Test
fun `kotlin rest assured example`() {
    given().
        param("firstName", "Johan").
        param("lastName", "Haleby").
    When().
        get("/greeting").
    then().
        statusCode(200).
        body("greeting.firstName", equalTo("Johan")).
        body("greeting.lastName", equalTo("Haleby"))
}

メソッド名のエスケープが不要になりました。
より詳しい内容は Johan Haleby のブログ記事 を参照してください。

23.2. Kotlin Extension Module

REST Assured 4.1.0 では kotlin-extensions モジュールを導入しました。
このモジュールは Kotlin から REST Assured を使用するときに便利な拡張関数を提供します。

Maven プロジェクトなら次のような依存ライブラリを追加します。

<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>kotlin-extensions</artifactId>
    <version>4.4.0</version>
    <scope>test</scope>
</dependency>

そして、io.restassured.module.kotlin.extensions パッケージの Given クラスを import 文に追加すると、次のように記述できます。

val message: String =
Given {
    port(7000)
    header("Header", "Header")
    body("hello")
} When {
    put("/the/path")
} Then {
    statusCode(200)
    body("message", equalTo("Another World"))
} Extract {
    path("message")
}

このモジュールは Kotlin 開発者にとって使いやすい API を提供するだけでなく、Java API として利用する場合でも次のような利点があります。

  1. 失敗した期待値の評価をまとめて報告できるようになります

  2. IDE でソースコードを整形してもきれいにインデントされます

拡張メソッドの名前は将来的に変更される可能性があります。
Kotlin 用の API に関する原則や利点については John Haleby のブログ記事 を参照してください。

23.3. Kotlin Extension Module for Spring MockMvc

REST Assured 4.1.0 では spring-mock-mvc モジュール の Kotlin 拡張に対応する spring-moc-mvc-kotlin-extensions モジュールを導入しました。
次のように記述できます。

class RestAssuredMockMvcKotlinExtensionsTest {

    @Test
    fun example() {
        val mockMvc =
            MockMvcBuilders.standaloneSetup(GreetingController())
                .build()

        val id: Int =
        Given {
            mockMvc(mockMvc)
            param("name", "Johan")
        } When {
            get("/greeting")
        } Then {
            body(
                "id", Matchers.equalTo(1),
                "content", Matchers.equalTo("Hello, Johan!")
            )
        } Extract {
            path("id")
        }

        assertThat(id).isEqualTo(1)
}

Maven プロジェクトなら次のような依存ライブラリを追加します。

<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>spring-mock-mvc-kotlin-extensions</artifactId>
    <version>4.4.0</version>
    <scope>test</scope>
</dependency>

必要な拡張関数を io.restassured.module.mockmvc.kotlin.extensions パッケージから import してください。

24. More info

For more information refer to the javadoc:

You can also have a look at some code examples:

If you need support then join the mailing list.

For professional support please contact johanhaleby.