yoi/docs/test-fixtures.md
2026-04-06 02:21:41 +09:00

5.0 KiB
Raw Blame History

テスト Fixture 仕様

概要

テスト用 fixture は、実 API のストリーミング応答を JSONL 形式で録画したファイル。 MockLlmClient::from_fixture() でロードし、API キー不要・決定的なテスト実行を実現する。

ファイル形式

{メタデータ行: JSON}
{イベント行: JSON}
{イベント行: JSON}
...
  • 1行目: メタデータ (timestamp, model, description)
  • 2行目以降: 録画イベント (elapsed_ms, event_type, data)
    • data フィールドに Event の JSON 文字列が入る

ファイル配置

crates/llm-worker/tests/fixtures/
  anthropic/
    simple_text.jsonl
    tool_call.jsonl
    long_text.jsonl
  openai/
    simple_text.jsonl
    tool_call.jsonl
    long_text.jsonl
  gemini/
    simple_text.jsonl
    tool_call.jsonl
    long_text.jsonl
  ollama/
    simple_text.jsonl
    tool_call.jsonl
    long_text.jsonl

シナリオ定義

simple_text

単純なテキスト応答。

項目
ファイル名 simple_text.jsonl
system prompt "You are a helpful assistant. Be very concise."
user message "Say hello in one word."
max_tokens 50
ツール なし

期待パターン:

  • BlockStart(Text) が1つ以上
  • BlockDelta(Text) が1つ以上
  • BlockStop(Text) が1つ以上
  • 応答が短い1単語程度

用途: 基本的なストリーミング動作、Timeline テキスト収集、Worker の単純な run 完了

tool_call

ツール呼び出しを含む応答。

項目
ファイル名 tool_call.jsonl
system prompt "You are a helpful assistant. Use tools when appropriate."
user message "What's the weather in Tokyo? Use the get_weather tool."
max_tokens 200
ツール get_weather(city: string)

期待パターン:

  • BlockStart(ToolUse) を含む
  • ToolUse ブロック内に tool_call_id, name: "get_weather" がある
  • tool input JSON に "city" キーを含む

用途: ToolCallCollector、Worker のツール実行フロー、Session の ToolResults ログ記録

long_text

長文テキスト応答。

項目
ファイル名 long_text.jsonl
system prompt "You are a creative writer."
user message "Write a short story about a robot discovering a garden. It should be at least 300 words."
max_tokens 1000
ツール なし

期待パターン:

  • BlockDelta(Text) が複数(ストリーミングチャンク)
  • 最終テキストが 300 語以上

用途: ストリーミングの分割配信検証、Subscriber のデルタ受信テスト

共通検証項目

全 fixture に対して以下を検証する(assert_* ヘルパー関数群):

  • assert_events_deserialize — 全イベントが Event にデシリアライズできる
  • assert_event_sequence — BlockStart → BlockDelta → BlockStop の基本シーケンス
  • assert_usage_tokensUsage イベントが含まれる
  • assert_timeline_integration — Timeline に流してテキスト収集できる

録画手順

前提

  • API キーが環境変数に設定されていること
  • crates/llm-worker ディレクトリで実行

コマンド

# 単一シナリオ録画
ANTHROPIC_API_KEY=... cargo run --example record_test_fixtures -- -s simple_text

# 全シナリオ録画
ANTHROPIC_API_KEY=... cargo run --example record_test_fixtures -- --all

# プロバイダー指定
OPENAI_API_KEY=... cargo run --example record_test_fixtures -- --all -c openai
GEMINI_API_KEY=... cargo run --example record_test_fixtures -- --all -c gemini

# モデル指定
ANTHROPIC_API_KEY=... cargo run --example record_test_fixtures -- --all -m claude-sonnet-4-20250514

シナリオ定義の場所

crates/llm-worker/examples/record_test_fixtures/scenarios.rs

新しいシナリオを追加する場合はこのファイルに TestScenario を追加し、 scenarios() 関数の返り値に含める。

録画後の確認チェックリスト

録画後、テストに組み込む前に以下を手動確認する:

  • JSONL の各行が valid JSON か(jq . < fixture.jsonl で確認)
  • 1行目にメタデータtimestamp, model, description)が入っているか
  • simple_text: BlockStartBlockDeltaBlockStop シーケンスがあるか
  • tool_call: BlockStart"block_type":"ToolUse" を含むか
  • long_text: BlockDelta が複数行あるか(ストリーミング分割の確認)
  • 各 fixture に Usage イベントが含まれるか
  • エラーイベントが混入していないか

注意事項

  • fixture は API の応答に依存するため、モデルバージョンアップで再録画が必要になることがある
  • 録画の自動化CI での定期録画等)は行わない。手動実行 + 目視確認のフロー
  • fixture が存在しない場合、対応するテストは skip される(if !fixture_path.exists() { return; } パターン)