既存の 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"が返ってくる
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 }
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
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.
1 つシナリオが実行されて
1 つパスして
0 つ落ちて
0 つスキップされた
とでた。なので OK
Body の json を覗いてみる
前回はレスポンスの中のステータスコードだけをみた。
今回はボディに詰まっている JSON データをみる。
そのためにボディの値をみてみる。
println(response.body().toString())
とりあえず今回作ったアプリのエンドポイントに対して、レスポンスの body を出してみようとするが、文字列が長すぎるためみれなかった。
example.com のエンドポイントで叩くと
(GET http://example.com) 200 <!doctype html> <html> <head> <title>Example Domain</title>
ちゃんと出る。HTML だから?
@Step("<json>が返る") fun shouldBeJson(json: String) { val json = ScenarioDataStore.get("JSON") println(json) json shouldBeEqualTo "persons.[0]" }
だが、kluent の shouldBeEqualTo で実際に適当な値でアサートしてみると
: Expected: <persons.[0]> but was: < {"persons":[ {"name":"Taro","age":10}, {"name":"Jiro","age":5}, {"name":"Saburo","age":3} ]} >
みることができた。
これをつかって実際の値をみることができた。
デバックモードで指定の位置で止めて、変数の値を覗く選択肢も有る。
これをうまいこと 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>
今回は maven の管理なので、POM.xml にこれをいれて実行する
<properties> <kotlin.version>1.5.32</kotlin.version> </properties>
kotlin の version up も必要なので、1.3 から 1.5 に上げた。
レスポンスの値を確認
{ "persons": [ { "name": "Taro", "age": 10 }, { "name": "Jiro", "age": 5 }, { "name": "Saburo", "age": 3 } ] }
この 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 }
persons の配列 1 つ目の key が value で返ってくるテストの実装を書いた
spec ファイルで呼び出す
# Person API のテスト ## Persons を取得する * Persons一覧をリクエストする * "200"が返ってくる * 1人目の"name"が"Taro"になっている
実行する
これを実行すると
❯ mvn test -DspecDir=specs/persons.spec # Person API のテスト ## Persons を取得する ✔ ✔ ✔ Successfully generated html-report to => gauge-kotlin/reports/html-report/index.html
ちゃんと通る。
これで 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 }
いまは決め打ちで 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 }
1 のとこも変数にして、配列の指定の順番の値もみれるようにした
テストの呼び出しとしては仕様書として、1 つめと書きたいが
プログラムでは配列は 0 始まりなので
実装で -1 してみるようにした。
## Persons を取得する * Persons一覧をリクエストする * "200"が返ってくる * "1"人目の"name"が"Taro"になっている * "2"人目の"name"が"Jiro"になっている * "3"人目の"name"が"Saburo"になっている
これで 3 つ呼び出して
# Person API のテスト ## Persons を取得する ✔ ✔ ✔ ✔ ✔
無事に通った。
まとめ
API リクエストをした結果のレスポンスをテストする。
そのためには リクエストするステップで ScenarioDataStore に put する。
次にアサート(確認)するステップで ScenarioDataStore から get する。
これで レスポンス の中身をテストできる。
レスポンスのボディの JSON の 指定のキーの値が特定の value になっていることを1つのステップでわかりやすくテストしたい。
そのためには JsonPathKt を使って
ScenarioDataStore から取り出したレスポンスのボディを
パースして、指定のパスの key と value をみる
これで
* Persons一覧をリクエストする * "200"が返ってくる * "1"人目の"name"が"Taro"になっている
このようにひと目みて、レスポンスの何をテストしているかがわかりやすい
API E2E を作ることができた。
伸びしろ
API リクエストをした結果のレスポンスのテストしかして無い。
さらに別の API にリクエストが飛ぶことも、飛んだリクエストをみて、
中身もパースしてテスト擦る必要が有る。
実際にデータをセットアップしてから試す必要も有る。
Top comments (0)