テストオラクル導出
そのテスト、何をもって「合格」とするかが曖昧なまま動いていませんか。
無料ベータ・面談制/正式版は有料提供予定
- 所要時間: 30分
- 進め方: 現場の状況をヒアリングし、最初に効くツールと順番を一緒に決めます
- ご準備は不要です
概要
「入力は作れるが期待結果が定まらない」状態(オラクル問題)を放置すると、通っても何も保証しないテストや、期待結果が人によってブレるテストになります。本ツールは期待結果の空白を埋め、合否を一意に判定できる検証可能なテストへ引き上げると同時に、オラクルを定義できない条件を仕様の穴として早期に可視化します。
効果
- 各検証可能条件に期待結果・合否判定基準・許容範囲・導出手法を付け、合否を一意に判定できるテストにする。
- オラクルを定義できない条件=仕様の穴を洗い出し、テスト前に仕様を詰められる。
- オラクルカバー率で「期待結果まで定まっている割合」を可視化する。
- 鍵が無くても検証可能条件の抽出と未定義の明示は動く(黙って空を返さない)。
インプット
- 仕様・要件文書
- 補足文脈(任意)
汎用LLMとの違い
オラクル導出のパターンカタログ(逆算・参照実装比較・プロパティ/不変条件・メタモルフィック・境界期待値)と導出手順が bubo 独自の中核です。汎用LLMに頼るより、捏造を避け(一意に定まらない条件は仕様の穴として明示)、検証可能条件を取りこぼさず網羅して期待結果を体系的に導きます。
テスト仕様から導いた合否条件の比較
同じテスト仕様を、汎用AIと test-oracle-deriver にそのまま渡した実際のやりとりです(要約ではありません)。
※ 実際は11行の表です。掲載スペースの都合で代表的な6行と末尾の備考を抜粋しました。 # 単体テスト仕様(alarm-controller) 対象: 各モジュール単体(trigger.py / outputs.py / battery.py / alarm_controller.py の個々の関数・メソッド)。 | No. | 対象REQ | テスト対象 | 前提条件 | 手順 | 期待結果 | |---|---|---|---|---|---| | UT-01 | REQ-A02 | `TriggerDetector.is_confirmed` | STANDBY相当。デバウンス済み信号(`pulled=True`が30ms分連続) | 連続して `is_confirmed()` を呼ぶ | 30ms経過時点で `True` を返す | | UT-03 | REQ-A11 | `TriggerDetector.is_confirmed` | `read_ms > READ_TIMEOUT_MS` のサンプルを渡す | `is_confirmed()` を呼ぶ | 直前の確定状態(変化なし)を返す | | UT-07 | REQ-A09 | `battery.BatteryMonitor.maybe_warn_low_battery` | 電圧を人為的に低下させた状態 | `maybe_warn_low_battery()` を呼ぶ | 何らかの結果(真偽値)が返ってくることを確認する | | UT-09 | REQ-A10 | `alarm_controller.load_state` | DBファイルが存在しない(未保存) | `load_state(path)` を呼ぶ | `"STANDBY"` が返る(安全側フォールバック) | | UT-10 | REQ-A05 | `AlarmController._handle_switch`(ALARM状態) | `state=="ALARM"`, スイッチ押下継続 1200ms分の `tick` を呼ぶ | `now_ms` を1000ms以上進めながら `tick` を複数回呼ぶ | `state` が `"STANDBY"` に変わる | | UT-11 | REQ-A05 | `AlarmController._handle_switch`(ALARM状態) | `state=="ALARM"`, スイッチ押下継続 500ms分のみ | `now_ms` を500ms分進めて `tick` を呼ぶ | `state` は `"ALARM"` のまま変化しない | 備考: - UT-07は「戻り値がNoneでない/何らかの真偽値であること」のみを確認しており、警告が実際に発生したか(電圧としきい値の関係)を検証していない弱いテストである。
導出結果の比較(導出件数: 本ツール 10件 / 汎用AI 11件)
| テスト仕様の行 | 本ツールが出したオラクル | 本ツールが付けた判定法 | 汎用AIが出した合否条件 |
|---|---|---|---|
| UT-01 デバウンス確定 | 30ms経過時点でTrueを返す | 仕様からの逆算 | 30ms連続で「True」/30ms前に「True」なら不合格 |
| UT-03 読み取りタイムアウト | 直前の確定状態(変化なし)を返す | 仕様からの逆算 | 確定状態が変化しないこと |
| UT-04 ブザー鳴動 | is_buzzer_active() が True になる | 仕様からの逆算 | 同左 |
| UT-05 LEDパターン | current_led_pattern() が "alarm_blink" になる | 仕様からの逆算 | 同左 |
| UT-06 電圧サンプリング | last_voltage が計測値で更新される | 仕様からの逆算 | 同左 |
| UT-07 低電圧警告 | (出力に含まれない) | — | 「戻り値がNoneでなく、何らかの真偽値であること」+弱いテストである旨の注記 |
| UT-08 状態の永続化 | "ALARM" が返る | 仕様からの逆算 | 同左 |
| UT-09 未保存時フォールバック | "STANDBY" が返る(安全側フォールバック) | 境界の期待値 | "STANDBY" が返ること |
| UT-10 長押し1200ms | state が "STANDBY" に変わる | 境界の期待値 | 同左 |
| UT-11 短押し500ms | state は "ALARM" のまま変化しない | 境界の期待値 | 同左 |
| UT-12 セルフテスト | True が返り state は変化しない | 仕様からの逆算 | 同左 |
## UT-06: battery.BatteryMonitor.sample
- **合格条件**: `sample()` 呼び出し後、`last_voltage` が `None` から実測値(数値)に更新されること
- **不合格**: `last_voltage` が `None` のまま、または更新されない
## UT-07: battery.BatteryMonitor.maybe_warn_low_battery
- **合格条件**: `maybe_warn_low_battery()` の戻り値が `None` ではなく、何らかの真偽値(`True`/`False`)であること
- **不合格**: `None` が返る、または例外発生
- **注記**: 仕様の備考にある通り、電圧としきい値の関係に基づく警告判定の正当性までは検証しない弱い判定条件
## UT-08: alarm_controller.persist_state / load_state(正常系)
- **合格条件**: `persist_state("ALARM", path)` 実行後に `load_state(path)` を呼ぶと `"ALARM"` が返ること
- **不合格**: `"ALARM"` 以外の値が返る、または例外発生
※ 実測全文は11件・約2,000字。上は連続する3件を抜粋したもので、文言の改変はありません。
- 条件: デバウンス済み信号(pulled=Trueが30ms分連続)に対しis_confirmed()を連続して呼ぶ 期待結果: 30ms経過時点でTrueを返す / 判定法: 仕様からの逆算 - 条件: read_ms > READ_TIMEOUT_MSのサンプルを渡してis_confirmed()を呼ぶ 期待結果: 直前の確定状態(変化なし)を返す / 判定法: 仕様からの逆算 - 条件: DBファイルが存在しない(未保存)状態でload_state(path)を呼ぶ 期待結果: "STANDBY"が返る(安全側フォールバック) / 判定法: 境界の期待値 - 条件: state=="ALARM"でスイッチ押下継続1200ms分のtickを呼ぶ 期待結果: stateが"STANDBY"に変わる / 判定法: 境界の期待値 - 条件: state=="ALARM"でスイッチ押下継続500ms分のみでtickを呼ぶ 期待結果: stateは"ALARM"のまま変化しない / 判定法: 境界の期待値 ※ 実測は10件。上は代表5件の抜粋で、文言の改変はありません。
テスト仕様のUT-07は期待結果が「何らかの真偽値が返ること」としか書かれていません。汎用AIはこれもそのまま合否条件として書き起こしましたが、本ツールは判定条件として成立しないものを導出せず10件を返し、各件に「仕様からの逆算/境界の期待値」という判定法のラベルを付けます。境界を突いているテストがどれかが、一覧のまま見分けられます。
社外秘のコードを、どう守るか
buboは入力を保存しません
ツールに渡したコード・仕様・データを、buboのサーバーは保存しません。bubo自身が学習に使うこともなく、処理はその場限りです。
AIに送るか・どこへ送るかは、あなたが握ります
標準のキーレス接続では、意味を読む処理は普段お使いのAIクライアントの中で実行されます。データの扱いは、お客様とそのプロバイダの既存のご契約のもとにあり、buboがAPIキーやコードをお預かりすることはありません。ご自身の契約するプロバイダを直接指定したい場合は、BYOK(Bring Your Own Key)として任意で設定できます。
AIに送らず動くツールも多くあります
多くのツールは決定的な静的解析だけで完結し、LLMに渡すのは必要な場面に限られます。AIに送る範囲を、あなた自身で絞り込めます。
ワンタイムコードは単回使用・有効期限7日・サーバーに平文保存はしません。発行したトークンは設定ファイルに直書きせず環境変数で参照します。既存のMCP設定がある場合も、壊さず冪等にマージします。
どう申し込み、どうつなぐのか
1. 面談を予約する
予約フォームから面談をお申し込みください。現在のQAの困りごとと、試したいツールをお聞かせいただきます。
2. 面談で適用先を一緒に決める
そろえたツールのうち、貴社の工程で効く順番をご一緒に見立てます。ワンタイムコードと接続コマンドは、面談後にあわせてお渡しします。
3. コード1つ、コマンド1行で接続
お受け取りしたワンタイムコードで、コマンドを1行実行(Windows / mac / Linux 各1行)。有効化・MCP設定(.mcp.json)生成・環境変数設定まで自動で完了します。あとはAIクライアント(Claude Code / Gemini CLI)を再起動するだけで、そのままQA方法論を呼び出せます。APIキーのご用意は不要です。ご自身の契約するLLMを使いたい場合は、BYOK(Bring Your Own Key)として任意で設定いただけます。