DEV Community

kaede
kaede

Posted on • Edited on

Kotlin Springboot -- Part 21 任意の key value の json を POST する API E2E を書く

why

前回の記事で /persons の GET の API E2E ができた
次に POST の API E2E を作りたい。


シナリオを定義する

## Persons を登録する
* "Siro""40"のデータで新規登録する
* "201"が返ってくる
Enter fullscreen mode Exit fullscreen mode

201 返ってくるところまでをテストする
UUID は見ない。UUID が生成された後に 201 が現れると想定する。


HTTP リクエストに データを詰めるため、依存を追加する

https://zetcode.com/kotlin/getpostrequest/

今回も get のテストを作った時と同じく
zetcode のやり方を参考にする

kotlin の map 型で定義した値を HttpRequest の body に詰められる形にするには objectMapper が必要。

objectMapper を使うためには jackson-module-kotlin のライブラリが必要。

しかし、JsonPathKt が暗黙的に jackson-module-kotlin に依存している。

よって、JsonPathKt が既に入っているこのプロジェクトでは jackson-module-kotlin は必要ない。

import com.fasterxml.jackson.databind.ObjectMapper

    @Step("<name>と<age>のデータで新規登録する")
    fun postPersonsWithData(name: String, age: Int) {
        val objectMapper = ObjectMapper();

    }
Enter fullscreen mode Exit fullscreen mode

このように、POM に jackson がなくても ObjectMapper を使うことができた。


リクエストのボディに突っ込める json 型に map 型から変換する

        val objectMapper = ObjectMapper();
        val values = mapOf("name" to name, "age" to age)
        val requestBody: String = objectMapper.writeValueAsString(values)
Enter fullscreen mode Exit fullscreen mode

import した ObjectMapper のインスタンスを作成して
引数から渡ってきた name と age を key value の kotlin map にする。

その kotlin map を objectMapper の writeValueAsString() に渡す。

こうすることで

 <{name=Siro, age=40}>
Enter fullscreen mode Exit fullscreen mode

map 型の key=value の、この形から

 <{"name":"Siro","age":40}>
Enter fullscreen mode Exit fullscreen mode

json 型の key:value の、この形に変換することができる。


json 型にした requestBody を使って POST リクエストを作成する

val request = HttpRequest.newBuilder()
    .uri(URI.create("http://127.0.0.1:8080/persons/"))
    .POST(HttpRequest.BodyPublishers.ofString(requestBody))
    .header("Content-Type", "application/json")
    .build();
Enter fullscreen mode Exit fullscreen mode

GET の時と同じように、
HttpRequest の newBuilder を使って基礎を作って
.uri(URI.create("your.url.com")) でURI からリクエストを作成する

POST の場合は .POST() で
HttpRequest の BodyPublishers を使って
先程作成したボディに値を詰めてリクエストを作成する。

さらに、.header で Content-Type に application/json を指定しないと、REST API では 415 Error になってしまう。
( これは参考にした記事には載っていなかった )


作成した body 込みのリクエストを送信してレスポンスを受け取れるようにする

これでリクエストは作れたので、送信して結果のレスポンスを受け取って
表示してみる。

val client = HttpClient.newBuilder().build();
val responseBodyHandler = HttpResponse.BodyHandlers.ofString()
val response = client.send(request, responseBodyHandler)

response shouldBeEqualTo "test"
Enter fullscreen mode Exit fullscreen mode

クライアントのインスタンスを作って
レスポンスのボディハンドラのインスタンスも作って

クライアントでリクエストとレスポンスのボディハンドラを使って送信する。

 Expected: <test> but was: 
<(POST http://127.0.0.1:8080/persons/) 405>
Enter fullscreen mode Exit fullscreen mode

中身をみてみると、ちゃんとレスポンスが入っている事がわかった。

まだ受け付けていないので、405 Method Not Allowed がでた。


レスポンスをシナリオデータストアに保存する

        ScenarioDataStore.put("StatusCode", response.statusCode())
Enter fullscreen mode Exit fullscreen mode

レスポンスのステータスコードをシナリオデータストアに保存する。
GET のときと同じ。

    @Step("<statusCode>が返ってくる")
    fun shouldBeStatusCode(statusCode: Int) {
        ScenarioDataStore.get("StatusCode") shouldBeEqualTo statusCode
    }
Enter fullscreen mode Exit fullscreen mode

これで、次のステップでステータスコードをアサートする事ができる。


実際に通しで実行してみる

## Persons を登録する
* "Siro""40"のデータで新規登録する
* "201"が返ってくる
Enter fullscreen mode Exit fullscreen mode

これでシナリオを実行すると

# Person API のテスト
  ## Persons を取得する  ✔ ✔ ✔ ✔ ✔
  ## Persons を登録する  ✔ ✘
        Failed Step: "201"が返ってくる
        Specification: specs/person.spec:12
        Error Message: org.amshove.kluent.internal.ComparisonFailedException: 
Expected: <201> but was: <405>
Enter fullscreen mode Exit fullscreen mode

しっかり POST でデータを詰めて実行されて
405 が返ってきてしまったことをテスト失敗として確認できた。
まだ API 実装してないからね。


まとめ

POST でデータを詰めて送って
結果をテストするためには

Spec ファイルのシナリオでデータを渡して
Step の実装で
データを map 型にして
jackson ライブラリの ObjectMapper で json 型に変換して
HttpRequest.BodyPublishers で Body に詰めた POST リクエストを作って

リクエストを送って、レスポンスをシナリオデータストアに保存して
次のステップでシナリオデータストアからレスポンスをアサートする。

以上。


伸びしろ

指定の json ファイルのデータを POST した結果のテストもしたい

Top comments (0)