Web API のテストの仕方
API のテストは、リクエストを送って、答えを確かめます。API の裏のコードは見ません。呼ぶ側が聞くことだけを聞き、答えを、API が約束したことと比べます。
確認を手で数個書き、失敗するものを1つ見て、リクエストを2回送ったときに何が起きるかを試します。
このレッスンのゴール
メモ
正しいリクエスト、間違ったリクエスト、再試行で API をテストし、各確認が何を示すかを言える。
重要な言葉
| ことば | いみ |
|---|---|
| テストケース | 1つのリクエストと、返ってくると期待する答え |
| 期待するステータス | API が返すはずのステータスコード |
| テストデータ | テストのためだけに作り、探して消せる行 |
| 再試行 | 最初の答えが届かなかったので、同じリクエストをまた送ること |
| 冪等 | 2回送っても、1回送ったあとと変わらないこと |
学生が入力するセルは、このプレビューでは空白です。
確認はリクエストと期待する番号
curl を打って数字を目で読むやり方は、数が増えると続きません。確認を一度だけ書きます。名前、期待するステータス、リクエストです。
まず psql にパスワードを渡し、books 表を作ります。そのあと、check という小さな関数を端末に定義します。リクエストを送り、PASS か FAIL を言う関数です。
psql にパスワードを渡す
export PGPASSWORD=shopここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
books 表を作る
psql -h db -U shop -c "drop table if exists books; create table books (id serial primary key, title text not null, year int not null, available boolean not null default true); insert into books (title, year, available) values ('海の地図', 1998, true), ('ヨーロッパの川', 2004, false), ('夜行列車', 2011, true); notify pgrst, 'reload schema'"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
check 関数を定義する
check() { want=$1; name=$2; shift 2; got=$(curl -s -o /dev/null -w '%{http_code}' "$@"); if [ "$got" = "$want" ]; then echo "PASS $name"; else echo "FAIL $name, wanted $want and got $got"; fi; }ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
正しいリクエストを確かめる
check 200 "本の一覧" "http://api:3000/books"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
失敗するはずのものを確かめる
check 200 "わざと間違い" "http://api:3000/nothing"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
断られるものをテストする
2つ目の確認は、関数が FAIL と言えると示すために、わざと間違えました。いつも PASS と出る確認は、ない方が悪いくらいです。
よいテスト一式は、正しいリクエストと同じだけ、間違ったリクエストに時間を使います。どれも正しいコードの 4xx で返り、データを変えてはいけません。
タイトルのない本を確かめる
check 400 "タイトルなし" -X POST -H "Content-Type: application/json" -d '{"year":2019}' "http://api:3000/books"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
JSON でない本文を確かめる
check 400 "壊れた JSON" -X POST -H "Content-Type: application/json" -d 'this is not json' "http://api:3000/books"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
テスト用の本の追加を確かめる
check 201 "本を追加" -X POST -H "Content-Type: application/json" -d '{"id":900,"title":"テスト本","year":2020}' "http://api:3000/books"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
同じ id をもう一度確かめる
check 409 "同じ id の再送" -X POST -H "Content-Type: application/json" -d '{"id":900,"title":"テスト本","year":2020}' "http://api:3000/books"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
ステータスだけでなく本文も確かめる
curl -s "http://api:3000/books?id=eq.900" | grep -q '"title":"テスト本"' && echo "PASS 本文にタイトルがある" || echo "FAIL 本文にタイトルがある"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
2回送られたリクエストをテストする
ネットワークは答えを失うので、クライアントは同じリクエストをまた送ります。2回送っても、1回送ったあとと同じデータなら、そのリクエストは冪等です。
行を数えて確かめます。まず値を設定する変更、次に、毎回新しい本を作るはずの、id なしの POST です。
同じ変更を2回送る
for i in 1 2; do curl -s -o /dev/null -w "%{http_code}\n" -X PATCH -H "Content-Type: application/json" -d '{"available":false}' "http://api:3000/books?id=eq.1"; doneここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
同じ新しい本を2回送る
for i in 1 2; do curl -s -o /dev/null -X POST -H "Content-Type: application/json" -d '{"title":"二重登録","year":2020}' "http://api:3000/books"; doneここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
「二重登録」の本を数える
psql -h db -U shop -At -c "select count(*) from books where title = '二重登録'"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
作成を再試行しても安全にする
「二重登録」が2冊あるのは、再試行が重複を作った、ということです。呼ぶ側が id を決めれば、作成を安全にできます。同じ id に、「もうあれば更新する」というヘッダーを付けて送ります。
1回目は201、2回目は200です。どちらも行は1つのままです。
安全な作成を2回送る
for i in 1 2; do curl -s -o /dev/null -w "%{http_code}\n" -X POST -H "Content-Type: application/json" -H "Prefer: resolution=merge-duplicates" -d '{"id":902,"title":"一度だけ","year":2020}' "http://api:3000/books"; doneここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
その id の行を数える
psql -h db -U shop -At -c "select count(*) from books where id = 902"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
例: 再試行しても安全なもの
| 2回送るリクエスト | 2回目のあとの行 | 再試行しても安全か |
|---|---|---|
| 1冊を available false にする PATCH | 1回目のあとと同じ | 安全。値を設定するから |
| id なしの本の POST | 1回目のあとより1行多い | 安全でない。重複ができる |
| id と merge-duplicates を付けた POST | 1回目のあとと同じ | 安全。id が行を決める |
| 本900の DELETE | 1回目で消え、そのまま消えている | 安全。ただしラボは両方で204を返す |
学生が入力するセルは、このプレビューでは空白です。
テスト用の行を消す
psql -h db -U shop -c "delete from books where id >= 900 or title = '二重登録'"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
よくある間違い
注意
正しいリクエストだけをテストして、失敗を一度も見ない人がいます。断られるものをテストしましょう。自分のテスト行も片付けます。片付けないと、2回目の実行が、1回目の残したデータに出会い、API と関係のない理由で失敗します。