既存の 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)