TT Lab
はじめる
学ぶ 学習パス コース

テストツール実戦

遅延評価を観測するエクスポートテスト

TT Labで続きを見る

目標

行の消費回数・改行のエスケープ・公開フィールド・レスポンス形式を検証します。

なぜ重要なのか

小さなリストでテストしたエクスポートのコードは正常に見えましたが、大きな入力をすべてlistに変換してメモリを使い果たしました。結果が同じだというだけでは、実行方式の契約まで同じだとはいえません。遅延消費を、目に見える状態に変える必要があります。

ステップ

  1. /root/work/test-lazy-export-lab/test_service.pyで、提供されたservice.pyの次の公開契約をテストしてください: validate_row(row)は、dictで、idがboolを除く正のint、nameが空でないstrのとき、rowを返します。それ以外はValueErrorです。追加の内部フィールドは許可します。正常な実装では成功し、この契約に違反する実装では、実際のテスト本文の失敗として検出する必要があります。前のステップのテストを維持したまま、test_関数を追加してください。

最初に1回だけ準備してください。既存のファイルは上書きしません。

mkdir -p /root/work/test-lazy-export-lab
test -e /root/work/test-lazy-export-lab/service.py || cp /opt/fixtures/ten_labs/test-lazy-export-lab/service.py /root/work/test-lazy-export-lab/service.py
test -e /root/work/test-lazy-export-lab/test_service.py || cp /opt/fixtures/ten_labs/test-lazy-export-lab/test_service.py /root/work/test-lazy-export-lab/test_service.py
cd /root/work/test-lazy-export-lab
  1. /root/work/test-lazy-export-lab/test_service.pyで、提供されたservice.pyの次の公開契約をテストしてください: project(row)は、validate_rowの後、idとnameだけを持つ新しいdictを返します。元の内部フィールドはそのまま保持します。正常な実装では成功し、この契約に違反する実装では、実際のテスト本文の失敗として検出する必要があります。前のステップのテストを維持したまま、test_関数を追加してください。

  2. /root/work/test-lazy-export-lab/test_service.pyで、提供されたservice.pyの次の公開契約をテストしてください: encode_line(row)は、projectの結果を、ensure_ascii=False、separators=(',',':')、sort_keys=TrueでJSONエンコードし、最後に' 'を1つ付けたstrです。name内の改行はJSONのエスケープである必要があります。正常な実装では成功し、この契約に違反する実装では、実際のテスト本文の失敗として検出する必要があります。前のステップのテストを維持したまま、test_関数を追加してください。

  3. /root/work/test-lazy-export-lab/test_service.pyで、提供されたservice.pyの次の公開契約をテストしてください: validate_max(value)は、boolを除く1–1000のintだけをそのまま返し、それ以外はValueErrorです。正常な実装では成功し、この契約に違反する実装では、実際のテスト本文の失敗として検出する必要があります。前のステップのテストを維持したまま、test_関数を追加してください。

  4. /root/work/test-lazy-export-lab/test_service.pyで、提供されたservice.pyの次の公開契約をテストしてください: take_rows(rows, maximum)は、isliceなどで最大maximum個だけを遅延して返すiteratorです。呼び出し時にmaximumを検証し、nextを1回呼ぶと入力を1回だけ消費します。正常な実装では成功し、この契約に違反する実装では、実際のテスト本文の失敗として検出する必要があります。前のステップのテストを維持したまま、test_関数を追加してください。

  5. /root/work/test-lazy-export-lab/test_service.pyで、提供されたservice.pyの次の公開契約をテストしてください: json_lines(rows, maximum=100)は、take_rowsから受け取った行ごとにencode_lineをyieldします。すべてを結合した文字列やリストは返しません。正常な実装では成功し、この契約に違反する実装では、実際のテスト本文の失敗として検出する必要があります。前のステップのテストを維持したまま、test_関数を追加してください。

  6. /root/work/test-lazy-export-lab/test_service.pyで、提供されたservice.pyの次の公開契約をテストしてください: decode_lines(text)は、splitlinesの空でない各行をjson.loadsしてvalidate_rowし、リストとして返します。空文字列は[]、空の中間行はValueErrorです。正常な実装では成功し、この契約に違反する実装では、実際のテスト本文の失敗として検出する必要があります。前のステップのテストを維持したまま、test_関数を追加してください。

  7. /root/work/test-lazy-export-lab/test_service.pyで、提供されたservice.pyの次の公開契約をテストしてください: create_app(rows)は、GET /exportでjson_lines(rows, 100)を、application/x-ndjsonのStreamingResponseとして返します。rowsは、再び反復可能なリストです。内部フィールドがなく、各行の内容と順序を保持する必要があります。正常な実装では成功し、この契約に違反する実装では、実際のテスト本文の失敗として検出する必要があります。前のステップのテストを維持したまま、test_関数を追加してください。

参考

行の契約を検証する(テスト)

/root/work/test-lazy-export-lab/test_service.pyで、提供されたservice.pyの次の公開契約をテストしてください: validate_row(row)は、dictで、idがboolを除く正のint、nameが空でないstrのとき、rowを返します。それ以外はValueErrorです。追加の内部フィールドは許可します。正常な実装では成功し、この契約に違反する実装では、実際のテスト本文の失敗として検出する必要があります。前のステップのテストを維持したまま、test_関数を追加してください。

最初に1回だけ準備してください。既存のファイルは上書きしません。

mkdir -p /root/work/test-lazy-export-lab
test -e /root/work/test-lazy-export-lab/service.py || cp /opt/fixtures/ten_labs/test-lazy-export-lab/service.py /root/work/test-lazy-export-lab/service.py
test -e /root/work/test-lazy-export-lab/test_service.py || cp /opt/fixtures/ten_labs/test-lazy-export-lab/test_service.py /root/work/test-lazy-export-lab/test_service.py
cd /root/work/test-lazy-export-lab

boolと数値を区別し、空の名前をエラーとして扱います。実装ファイルは修正しません。pytest.raisesで期待する例外を確認し、正常な結果には具体的な期待値をassertしてください。

保存後、bash /opt/lab/checks/test-lazy-export-lab/01-contract.shで確認してください。

公開する行だけを作る(テスト)

/root/work/test-lazy-export-lab/test_service.pyで、提供されたservice.pyの次の公開契約をテストしてください: project(row)は、validate_rowの後、idとnameだけを持つ新しいdictを返します。元の内部フィールドはそのまま保持します。正常な実装では成功し、この契約に違反する実装では、実際のテスト本文の失敗として検出する必要があります。前のステップのテストを維持したまま、test_関数を追加してください。

エクスポートの経路にも、通常のAPIと同じ公開フィールドのポリシーを適用する必要があります。実装ファイルは修正しません。pytest.raisesで期待する例外を確認し、正常な結果には具体的な期待値をassertしてください。

保存後、bash /opt/lab/checks/test-lazy-export-lab/02-contract.shで確認してください。

行の境界を保ったままエンコードする(テスト)

/root/work/test-lazy-export-lab/test_service.pyで、提供されたservice.pyの次の公開契約をテストしてください: encode_line(row)は、projectの結果を、ensure_ascii=False、separators=(',',':')、sort_keys=TrueでJSONエンコードし、最後に' 'を1つ付けたstrです。name内の改行はJSONのエスケープである必要があります。正常な実装では成功し、この契約に違反する実装では、実際のテスト本文の失敗として検出する必要があります。前のステップのテストを維持したまま、test_関数を追加してください。

文字列の連結でJSONを作ると、引用符や改行で形式が壊れます。実装ファイルは修正しません。pytest.raisesで期待する例外を確認し、正常な結果には具体的な期待値をassertしてください。

保存後、bash /opt/lab/checks/test-lazy-export-lab/03-contract.shで確認してください。

出力件数の上限を検証する(テスト)

/root/work/test-lazy-export-lab/test_service.pyで、提供されたservice.pyの次の公開契約をテストしてください: validate_max(value)は、boolを除く1–1000のintだけをそのまま返し、それ以外はValueErrorです。正常な実装では成功し、この契約に違反する実装では、実際のテスト本文の失敗として検出する必要があります。前のステップのテストを維持したまま、test_関数を追加してください。

無限の入力を誤って最後まで読み込まないように、呼び出し側に上限を要求します。実装ファイルは修正しません。pytest.raisesで期待する例外を確認し、正常な結果には具体的な期待値をassertしてください。

保存後、bash /opt/lab/checks/test-lazy-export-lab/04-contract.shで確認してください。

必要な行だけを消費する(テスト)

/root/work/test-lazy-export-lab/test_service.pyで、提供されたservice.pyの次の公開契約をテストしてください: take_rows(rows, maximum)は、isliceなどで最大maximum個だけを遅延して返すiteratorです。呼び出し時にmaximumを検証し、nextを1回呼ぶと入力を1回だけ消費します。正常な実装では成功し、この契約に違反する実装では、実際のテスト本文の失敗として検出する必要があります。前のステップのテストを維持したまま、test_関数を追加してください。

list(rows)に変換した瞬間に、無限の入力や大容量の入力を処理できなくなります。実装ファイルは修正しません。pytest.raisesで期待する例外を確認し、正常な結果には具体的な期待値をassertしてください。

保存後、bash /opt/lab/checks/test-lazy-export-lab/05-contract.shで確認してください。

行を遅延してシリアライズする(テスト)

/root/work/test-lazy-export-lab/test_service.pyで、提供されたservice.pyの次の公開契約をテストしてください: json_lines(rows, maximum=100)は、take_rowsから受け取った行ごとにencode_lineをyieldします。すべてを結合した文字列やリストは返しません。正常な実装では成功し、この契約に違反する実装では、実際のテスト本文の失敗として検出する必要があります。前のステップのテストを維持したまま、test_関数を追加してください。

オブジェクトの選択と表現の変換を、それぞれ遅延ステップのまま保ちます。実装ファイルは修正しません。pytest.raisesで期待する例外を確認し、正常な結果には具体的な期待値をassertしてください。

保存後、bash /opt/lab/checks/test-lazy-export-lab/06-contract.shで確認してください。

ダウンロードした行を再検証する(テスト)

/root/work/test-lazy-export-lab/test_service.pyで、提供されたservice.pyの次の公開契約をテストしてください: decode_lines(text)は、splitlinesの空でない各行をjson.loadsしてvalidate_rowし、リストとして返します。空文字列は[]、空の中間行はValueErrorです。正常な実装では成功し、この契約に違反する実装では、実際のテスト本文の失敗として検出する必要があります。前のステップのテストを維持したまま、test_関数を追加してください。

空のファイルと、形式が壊れた空のレコードを区別します。実装ファイルは修正しません。pytest.raisesで期待する例外を確認し、正常な結果には具体的な期待値をassertしてください。

保存後、bash /opt/lab/checks/test-lazy-export-lab/07-contract.shで確認してください。

HTTPダウンロードを完成させる(テスト)

/root/work/test-lazy-export-lab/test_service.pyで、提供されたservice.pyの次の公開契約をテストしてください: create_app(rows)は、GET /exportでjson_lines(rows, 100)を、application/x-ndjsonのStreamingResponseとして返します。rowsは、再び反復可能なリストです。内部フィールドがなく、各行の内容と順序を保持する必要があります。正常な実装では成功し、この契約に違反する実装では、実際のテスト本文の失敗として検出する必要があります。前のステップのテストを維持したまま、test_関数を追加してください。

Content-Typeだけをストリーミングと書いて、内部ではすべてを集めていないかを、ジェネレーターのテストと合わせて確認します。実装ファイルは修正しません。pytest.raisesで期待する例外を確認し、正常な結果には具体的な期待値をassertしてください。

保存後、bash /opt/lab/checks/test-lazy-export-lab/08-contract.shで確認してください。