テスト
ZeroClaw は、ファイルシステムのレイアウトに基づいた5段階のテスト分類体系を採用しています。各段階にはそれぞれ異なる境界と異なるコストがあります。証明したい内容を証明できる最も低い段階を選んでください。
ユーザーが直接実行、クリック、送信、インストール、または観察する挙動を PR が主張する場合は、ユーザー境界の証拠 を使用して、その境界に到達する最小のテストまたは手動確認を特定します。
5つのレベル
| レベル | テスト内容 | 境界 | どこに存在するか |
|---|---|---|---|
| ユニット | 単一の関数または構造体 | すべてモック | src/** または隣接する tests.rs 内の #[cfg(test)] ブロック |
| コンポーネント | 境界内にある1つのサブシステム | サブシステムは実装、他はすべてモック | tests/component/ |
| 統合 | 複数の内部コンポーネントが配線されている | 実際の内部実装を使用し、外部APIはモック | tests/integration/ |
| システム | 内部境界全体でのリクエストからレスポンスまで | 外部APIのみモック | tests/system/ |
| ライブ | 外部のリアルサービスを使用したフルスタック | 何もモックされておらず、#[ignore] になっています | tests/live/ |
テスト以外の2つのディレクトリ:
| ディレクトリ | 目的 |
|---|---|
tests/manual/ | 人手で実行するテストスクリプト(shell、Python)。cargo経由ではなく直接実行します |
tests/support/ | 共有モックインフラストラクチャ。テストバイナリではなく、各レベルから mod support; として組み込まれます |
テストの実行
sh
cargo test # ユニット + コンポーネント + インテグレーション + システム
cargo test --lib # ユニットのみ
cargo test --test component # コンポーネントのみ
cargo test --test integration # インテグレーションのみ
cargo test --test system # システムのみ
cargo test --test live -- --ignored # live(API認証情報が必要)
cargo test --test integration agent # レベル内のフィルタ
cargo nextest run --locked --workspace --exclude zeroclaw-desktop # 実行される CI
./scripts/ci/parallel_runtime_test_gate.sh # 同一プロセスでのランタイム/チャネルの反復テスト
./dev/ci.sh all # CI フルバッテリー (Docker)
./dev/ci.sh firmware-protocol # スタンドアロンのファームウェアプロトコルホストゲート(Docker)
./dev/ci.sh test-component # レベル別CIコマンド(Docker)
firmware-protocol コマンドは、ルートの Cargo ワークスペース外にあるスタンドアロンの firmware/zeroclaw-fw-protocol クレートをチェックします。scripts/ci/firmware_protocol_gate.sh は、そのフォーマット、strict Clippy、および locked-test チェックの正規の定義であり、必須の CI と pre-push フックは同じヘルパーを呼び出します。
並列ランタイムゲートは、zeroclaw-runtime と zeroclaw-channels のライブラリテストバイナリ全体を、16 個のハーネススレッドで繰り返し実行します。バイナリ全体を実行するのは意図的です。状態を変更するテストと、それ以外では無関係なエージェントのターンとの間の干渉を検出できるためです。フィルタリングされたテスト実行では、この干渉を検出できません。必須 CI では、いずれかのクレート、ワークスペースの依存関係マニフェスト、またはゲート自身の CI ファイルに変更がある場合、このゲートを別のジョブで実行します。その他の PR ではこれをスキップします。master へのプッシュとマージキューの実行では、完全な回帰検証のバックストップが維持されます。繰り返し回数は ZEROCLAW_PARALLEL_TEST_RUNS で、ハーネススレッド数は ZEROCLAW_PARALLEL_TEST_THREADS で上書きできます。
新しいテストのレベルを選択する
tests/component/- 複数のコンポーネントを配線してテストする場合は →
tests/integration/ tests/system/でフルメッセージフローをエンドツーエンドでテストする?tests/live/ディレクトリ内の#[ignore]属性付きテストは、実際の API キーが必要です。
ファイルを作成したら、それをレベルの mod.rs に追加し、tests/support/ から共有インフラストラクチャを使用してください。
共有インフラ
すべてのテストバイナリには mod support; が含まれており、共有モックは crate::support::* として利用可能です。
| モジュール | 目次 |
|---|---|
mock_model_provider.rs | MockModelProvider(FIFO スクリプト方式)、RecordingModelProvider(リクエストをキャプチャ)、TraceLlmModelProvider(JSON フィクスチャの再生) |
mock_tools.rs | EchoTool、CountingTool、FailingTool、RecordingTool |
mock_channel.rs | TestChannel(送信をキャプチャし、タイピングイベントを記録) |
helpers.rs | make_memory()、make_observer()、build_agent()、text_response()、tool_response()、StaticRecallMemory |
trace.rs | LlmTrace、TraceTurn、TraceStep 型 + LlmTrace::from_file() |
assertions.rs | verify_expects() は宣言的トレースアサーション用 |
一般的な使用方法:
#![allow(unused)]
fn main() {
use crate::support::{MockModelProvider, EchoTool, CountingTool};
use crate::support::helpers::{build_agent, text_response, tool_response};
}
JSONトレースフィクスチャ
トレースフィクスチャは、tests/fixtures/traces/ に JSON ファイルとして保存される、あらかじめ用意された LLM 応答スクリプトです。これらはインラインのモック設定を宣言的な会話スクリプトに置き換えるもので、mockall のチェーンよりもはるかに読みやすく編集しやすくなっています。
仕組み:
TraceLlmModelProviderはフィクスチャを読み込み、ModelProviderトレイトを実装します。- 各
provider.chat()の呼び出しは、フィクスチャからFIFO順に次のステップを返します。 - 実際のツールは正常に実行されます(
EchoToolは引数を実際に処理します)。 - すべてのターンが終了した後、
verify_expects()は宣言的アサーションを確認します。 - エージェントがプロバイダーをステップ数よりも多く呼び出すと、テストは失敗します。
フィクスチャ形式:
{
"モデル名": "テスト名",
ターン: [
{
「user_input」: 「ユーザーメッセージ」,
ステップ: [
{
response: {
"type": "text",
"内容": 「LLMの応答」,
"input_tokens": 20,
"出力トークン": 10
}
}
]
}
],
「期待」: {
`response_contains`: ["期待されるテキスト"],
"使用されたツール": ["echo"],
"max_tool_calls": 1
}
}
レスポンスのタイプ: "text" (プレーンテキスト) または "tool_calls" (LLM がツール実行をリクエスト)。
次のフィールドを期待します: response_contains, response_not_contains, tools_used, tools_not_used, max_tool_calls, all_tools_succeeded, response_matches (正規表現)。
ライブテストの規約
ライブテストは実際の外部サービスにアクセスし、実際の費用が発生します。デフォルトでは #[ignore] が設定されており、明示的にオプトインした場合のみ実行されます。
- 常に
#[ignore]を使用してください。通常のcargo testでライブテストが実行されないようにしてください。 env::var("ZEROCLAW_TEST_*")から認証情報を読み込みます。オペレーターの設定は読み込まないでください。ライブテストはhermetic(外部依存のない自己完結した状態)であるべきです。cargo test --test live -- --ignored --nocaptureで実行してください。
データベーステストは統合テストです
スキーマや SQL を扱うテストでは SQLite をモックしないこと。統合テストは実際のデータベースに対して実行する必要があります。「モックは通るが本番では失敗する」という種類のバグは実在し、過去にそれで痛い目を見たことがあります。
手動テスト
tests/manual/ には、cargo test による自動化が不可能な手動テスト用のスクリプトが格納されています。これらは直接実行してください。チャンネル固有の手動スモークテストは tests/manual/<channel>/ の下に配置されています。