DEV Community

kaede
kaede

Posted on • Updated on

Kotlin Springboot -- Part 20 API E2E で作成したアプリにリクエストしたレスポンスの JSON を key 毎にテストする

既存の GET の 200 の確認テストのコードと動作の確認

https://dev.to/kaede_io/kotlin-springboot-part-10-api-e2e-wozuo-ru-3fji

前回レスポンスが 200 返ってくるかどうかのテストは作り終えた。

gauge で kotlin プロジェクトを作る手順に関してはこちら。


Spec ファイル

# Person API のテスト

## Persons を取得する
* Persons一覧をリクエストする
* "200"が返ってくる
Enter fullscreen mode Exit fullscreen mode

src/specs/person.spec

にこのマークダウンでシナリオを書いて


Step の実装ファイル

src/test/kotlin/StepImplementation.kt

にそのシナリオの実装を書く。

Step < Scenario < Spec

この粒度になっている。

    @Step("Persons一覧をリクエストする")
    fun requestPersons() {
        val client = HttpClient.newBuilder().build();
        val request = HttpRequest.newBuilder()
        .uri(URI.create("http://127.0.0.1:8080/persons/"))
            .build();
        val response = client.send(request, HttpResponse.BodyHandlers.ofString());
        ScenarioDataStore.put("StatusCode", response.statusCode())
    }
    @Step("<statusCode>が返ってくる")
    fun shouldBeStatusCode(statusCode: Int) {
        ScenarioDataStore.get("StatusCode") shouldBeEqualTo statusCode
    }
Enter fullscreen mode Exit fullscreen mode

localhost8080/persons に HTTP リクエストを送り
データストアに StatusCode というキーでレスポンスのステータスコードを入れる。

そしてデータストアに引数の数値が入っているか確認している。

なお、localhost には HttpClient からリクエストできない。

https://stackoverflow.com/a/35458792

web リクエストをするためだから、HTTP か HTTPS じゃないとだめらしい

https://stackoverflow.com/a/51037827

127 から始まる実際の自分を参照する IP にすれば良いらしい。

なので localhost ではなく http 127.0.0.1 にする


実行する

https://docs.gauge.org/execution.html?os=linux&language=javascript&ide=vscode

gauge 公式をみると引数が書いてある

mvn test -DspecsDir=specs/persons.spec 
Enter fullscreen mode Exit fullscreen mode

spec ファイルのパスを -DspecDir= で指定して mvn test で実行

:line でシナリオも指定できる

# Person API のテスト
  ## Persons を取得する  ✔ ✔

Successfully generated html-report to => 
/home/ryo/source/gauge-kotlin/reports/
html-report/index.html

Specifications: 1 executed      1 passed        0 failed        0 skipped
Scenarios:      1 executed      1 passed        0 failed        0 skipped

Total time taken: 467ms
Updates are available. Run `gauge update -c` for more info.
Enter fullscreen mode Exit fullscreen mode

1 つシナリオが実行されて
1 つパスして
0 つ落ちて
0 つスキップされた

とでた。なので OK



Body の json を覗いてみる

前回はレスポンスの中のステータスコードだけをみた。

今回はボディに詰まっている JSON データをみる。

そのためにボディの値をみてみる。

println(response.body().toString())
Enter fullscreen mode Exit fullscreen mode

とりあえず今回作ったアプリのエンドポイントに対して、レスポンスの body を出してみようとするが、文字列が長すぎるためみれなかった。

example.com のエンドポイントで叩くと

(GET http://example.com) 200
<!doctype html>
<html>
<head>
<title>Example Domain</title>
Enter fullscreen mode Exit fullscreen mode

ちゃんと出る。HTML だから?

    @Step("<json>が返る")
    fun shouldBeJson(json: String) {
        val json = ScenarioDataStore.get("JSON")
        println(json)
        json shouldBeEqualTo "persons.[0]"
    }
Enter fullscreen mode Exit fullscreen mode

だが、kluent の shouldBeEqualTo で実際に適当な値でアサートしてみると

: Expected: <persons.[0]> 
but was: <
{"persons":[
{"name":"Taro","age":10},
{"name":"Jiro","age":5},
{"name":"Saburo","age":3}
]}
>
Enter fullscreen mode Exit fullscreen mode

みることができた。
これをつかって実際の値をみることができた。

デバックモードで指定の位置で止めて、変数の値を覗く選択肢も有る。

これをうまいこと key:value の map にすればテストできる。

JSONPath を使えばパースできるらしいので試してみる。



JsonPathKt を使ってレスポンスのボディの JSON をキー毎にテストする

https://github.com/codeniko/JsonPathKt

Java で有名な JSONPath の Kotlin 版があるらしい。


JsonPathKt を 依存関係に追加して kotlin を 1.5 に更新

        <dependency>
            <groupId>com.nfeld.jsonpathkt</groupId>
            <artifactId>jsonpathkt</artifactId>
            <version>2.0.1</version>
        </dependency>
Enter fullscreen mode Exit fullscreen mode

今回は maven の管理なので、POM.xml にこれをいれて実行する

    <properties>
        <kotlin.version>1.5.32</kotlin.version>
    </properties>
Enter fullscreen mode Exit fullscreen mode

kotlin の version up も必要なので、1.3 から 1.5 に上げた。


レスポンスの値を確認


{
  "persons": [
    {
      "name": "Taro",
      "age": 10
    },
    {
      "name": "Jiro",
      "age": 5
    },
    {
      "name": "Saburo",
      "age": 3
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

この JSON に対してテストする。


Step の実装として、JsonPath の read でパースして指定位置の値をテストする

    @Step("1人目の<key>が<value>になっている")
    fun shouldNameBeValue(key: String, value: String) {
        val json= ScenarioDataStore.get("JSON") as String
        val parsedJson = JsonPath.parse(json)?.read<String>("$.persons[0].$key")
        parsedJson shouldBeEqualTo value
    }
Enter fullscreen mode Exit fullscreen mode

persons の配列 1 つ目の key が value で返ってくるテストの実装を書いた


spec ファイルで呼び出す

# Person API のテスト

## Persons を取得する
* Persons一覧をリクエストする
* "200"が返ってくる
* 1人目の"name"が"Taro"になっている
Enter fullscreen mode Exit fullscreen mode

実行する

これを実行すると

❯ mvn test -DspecDir=specs/persons.spec


# Person API のテスト
  ## Persons を取得する  ✔ ✔ ✔

Successfully generated html-report to 
=> gauge-kotlin/reports/html-report/index.html
Enter fullscreen mode Exit fullscreen mode

ちゃんと通る。

これで key value を指定して、
spec での呼び出しで API リクエストした、
レスポンスのボディの JSON をテストすることができるようなった。


1 つめだけでなく、指定の序数もみれるようにする

    @Step("1人目の<key>が<value>になっている")
    fun shouldNameBeValue(key: String, value: String) {
        val json= ScenarioDataStore.get("JSON") as String
        val parsedJson = JsonPath.parse(json)?.read<String>("$.persons[0].$key")
        parsedJson shouldBeEqualTo value
    }
Enter fullscreen mode Exit fullscreen mode

いまは決め打ちで 1 人目限定でみてしまっている

    @Step("<number>人目の<key>が<value>になっている")
    fun shouldNameBeValue(number: Int, key: String, value: String) {
        val json= ScenarioDataStore.get("JSON") as String
        val parsedJson = JsonPath.parse(json)?.read<String>("$.persons[${number-1}].$key")
        parsedJson shouldBeEqualTo value
    }
Enter fullscreen mode Exit fullscreen mode

1 のとこも変数にして、配列の指定の順番の値もみれるようにした
テストの呼び出しとしては仕様書として、1 つめと書きたいが
プログラムでは配列は 0 始まりなので
実装で -1 してみるようにした。

## Persons を取得する
* Persons一覧をリクエストする
* "200"が返ってくる
* "1"人目の"name"が"Taro"になっている
* "2"人目の"name"が"Jiro"になっている
* "3"人目の"name"が"Saburo"になっている
Enter fullscreen mode Exit fullscreen mode

これで 3 つ呼び出して

# Person API のテスト
  ## Persons を取得する  ✔ ✔ ✔ ✔ ✔
Enter fullscreen mode Exit fullscreen mode

無事に通った。



まとめ

API リクエストをした結果のレスポンスをテストする。
そのためには リクエストするステップで ScenarioDataStore に put する。
次にアサート(確認)するステップで ScenarioDataStore から get する。

これで レスポンス の中身をテストできる。

レスポンスのボディの JSON の 指定のキーの値が特定の value になっていることを1つのステップでわかりやすくテストしたい。

そのためには JsonPathKt を使って
ScenarioDataStore から取り出したレスポンスのボディを
パースして、指定のパスの key と value をみる

これで

* Persons一覧をリクエストする
* "200"が返ってくる
* "1"人目の"name"が"Taro"になっている
Enter fullscreen mode Exit fullscreen mode

このようにひと目みて、レスポンスの何をテストしているかがわかりやすい
API E2E を作ることができた。

伸びしろ

API リクエストをした結果のレスポンスのテストしかして無い。
さらに別の API にリクエストが飛ぶことも、飛んだリクエストをみて、
中身もパースしてテスト擦る必要が有る。

実際にデータをセットアップしてから試す必要も有る。

Top comments (0)