📌 この記事を5行でまとめると
- 2026年8月に手動Mutation 11件を経験し、今回は Codexを活用してPhase 0〜25の大規模再監査を実施しました。
- 重複を除いたMutationは 1,286件、最終観測は KILLED 1,190 / SURVIVED 68 / ERROR 27 / TIMEOUT 0 / EQUIVALENT 1 でした。
- CodexにはMutationの実行・pytestの強化・証拠の整理を任せ、人間側で監査方針・判定基準・終了条件を管理しました。
- 保存済み証拠で確認できるpytest追加は 193ケース。最終PhaseではTask関連の8件をすべてKILLED化しました。
- 正式採用したpytestだけを最新版mainへ移植し、991 passed / 18 skipped / 0 failed を確認。PR #81をmergeしました。
はじめに
本業でトラックドライバーとして働きながら、AIを活用してPython / Flaskを中心にWebアプリを個人開発しているtosane932 です。
2026年5月12日からPythonを学び始め、現在は個人開発した作品を Tosane Works としてまとめています。
今回も、その中のベーカリー店舗向けWebアプリ Bakery Hub の話です。
2026年8月15日、私はすでにMutation Testingについて記事を書いています。
📝pytestを「事故防止台帳」として育てる 第5段階:GREENを疑い、Mutation Testingで「本当に守れているか」を検証した
当時は87件のpytestに対して、手動Mutationを11件実施しました。
最初は5件のSURVIVEDが見つかり、fixtureやassertを強化して、最終的には11件すべてをKILLEDにできました。
つまり、pytestがGREENであることと、実際の故障を検知できることは別という問題は、以前から意識していました。
それから約2か月。
Bakery Hubには新しい機能が増え、pytestも756件まで増加しました。
そこで今度は、
以前の11件だけでなく、もっと広い範囲を確認したい。
自分で選んだ故障だけでなく、思いつかなかった故障候補も調べたい。
と考えました。
ただ、今回の監査は以前とは作業方法が異なります。
今回はCodexを活用しました。
Codexに監査条件を指示し、コードへのMutation適用、pytest実行、結果の記録、テスト強化などを進めてもらう方法です。
さらに途中からCosmic Rayも導入しました。
前回の記事では、今回の再監査を始めてからCosmic Rayを導入するまでの流れを書いています。
今回はその続きとして、2026年10月3日〜7日の5日間に行ったPhase 0〜25の監査結果と、最後にmainへ反映するまでをまとめます。
今回は「手動11件」と何が違ったのか
最初に、8月と今回の違いを整理します。
| 比較項目 | 2026年8月 | 2026年10月 |
|---|---|---|
| Mutation数 | 11件 | 1,286件 |
| 作業方法 | 自分で手動検証 | Codexへ監査を指示 |
| Mutationツール | 専用ツールなし | Cosmic Rayも併用 |
| 主な対象 | 代表的な故障 | Phase 0〜25の広範囲 |
| 人間の役割 | 故障の適用・検証 | 監査方針・判定基準・終了条件の管理 |
| 最終成果 | 検証不足を補強 | 正式pytestを強化してmainへ反映 |
今回新しく取り組んだのは、単にMutationの数を増やすことだけではありません。
AIに大量の検証作業を任せながら、
どの条件でKILLEDと認めるか、どんな証拠を残すか、どこで監査を終了するか
を管理することも、重要な課題でした。
最初に、5日間の監査結果
まずは全体の結果です。
| 項目 | 結果 |
|---|---|
| 手動方式のMutation | 60件 |
| Cosmic Ray | 1,226件 |
| Mutation合計(重複除外) | 1,286件 |
| KILLED | 1,190件 |
| SURVIVED | 68件 |
| ERROR | 27件 |
| TIMEOUT | 0件 |
| EQUIVALENT | 1件 |
| 証拠で確認できるpytest追加 | 193ケース |
Mutationの分類は次のとおりです。
| 判定 | 意味 |
|---|---|
| KILLED | 変更したコードの故障をpytestが検知した |
| SURVIVED | Mutationを入れても検知されなかった |
| ERROR | Mutationの実行・判定中にエラーが発生した |
| TIMEOUT | 設定時間内に実行が終了しなかった |
| EQUIVALENT | コードが変化しても、対象の動作に実質的な違いがないと判断した |
ここで重要なのは、SURVIVEDが68件、ERRORが27件残っていることです。
つまり、1,286件すべてについて検知能力を証明できたわけではありません。
また、193ケースという数字は保存済みの監査証拠から確認できた追加pytest数です。
後述するPR #81のテスト収集件数の増分とは別の数字になります。
8月の11件で終わらせなかった理由
8月のMutation Testingでは、代表的な11件の故障を検証しました。
その経験から、正常なpytestが通ることと、故障を検知できることは別だと理解していました。
しかし、その後もBakery Hubの開発は続いています。
商品登録、日次売上、Dashboard、Guest Demo、材料発注、店舗メモ、Task管理など、機能が増えるたびにpytestも追加してきました。
通常の開発では、
機能追加
↓
pytest追加
↓
pytest GREEN
↓
GitHub ActionsもGREEN
という流れを繰り返しています。
これは必要な確認です。
ただ、機能が増えれば、検証すべき条件や操作の組み合わせも増えます。
以前確認した11件だけでは、新しい機能まで十分に調べたとはいえません。
今回確認したかったのは、
増え続けたpytestが、どこまで故障を検知できる状態になっているか
ということでした。
監査の開始時点
2026年10月3日、今回の再監査を始めた時点のpytestは次の状態でした。
| 項目 | 開始時Baseline |
|---|---|
| collected | 774 |
| passed | 756 |
| failed | 0 |
| skipped | 18 |
| warnings | 9 |
すでに756件のpytestが通っていました。
しかし今回確認するのは、テストの件数ではありません。
各テストが、どの故障を検知できるかです。
この考え方は8月から変わっていません。
今回はそれを、Codexを使って広い範囲へ適用することにしました。
Codexへ監査を任せる前にルールを決める
今回のように大量のコード変更とpytest実行をAIへ任せる場合、単に、
Mutation Testingをやってください。
だけでは、監査の範囲や判定方法が曖昧になります。
そこで、実行前に条件を決めました。
主な監査ルール
| 項目 | ルール |
|---|---|
| 作業場所 | 監査用branchで実施 |
| Mutation | 正常コードへ一時的に適用 |
| DB | 隔離されたテスト用DBを使用 |
| 本番環境 | 接続・変更しない |
| KILLED判定 | 狙った故障をpytestが検知したことを確認 |
| SURVIVED | 原因を分類してから対応 |
| pytest強化 | 正式仕様に沿ったテストのみ追加 |
| 復元 | Mutation適用後は正常コードへrestore |
| 証拠 | 実行結果・判定・復元状態を記録 |
| 終了 | PhaseごとのGateを確認 |
ここで特に重視したのは、
pytestがREDになった理由まで確認すること
です。
例えば、Mutationを適用したあとにHTTP 500が返ったり、予想外の例外が発生したりする場合があります。
しかし、それだけでは対象の故障を検知できたとは限りません。
狙ったassertでREDになったのかを確認し、正式なテスト強化として認める条件を決めました。
AIへ実行を任せても、判定基準まで曖昧にしないためです。
Phase 0〜6|Codexで手動方式のMutationを60件実施
最初は専用Mutationツールを使わず、Codexにコード変更と検証を実行してもらいました。
Phase 0でBaselineと監査条件を確認し、Phase 1〜6で各10件のMutationを実施しました。
| Phase | 主な監査対象 | Mutation |
|---|---|---|
| 1 | 商品登録 | 10件 |
| 2 | 日次売上 | 10件 |
| 3 | Dataset分離 | 10件 |
| 4 | Guest関連 | 10件 |
| 5 | 店舗ツール | 10件 |
| 6 | 再送・操作順序 | 10件 |
| 合計 | 60件 |
商品名の長さ、数量の境界、Datasetの取り違え、DB保存失敗、連続操作など、実際の不具合につながりそうな変更を対象にしました。
最初の結果は次のとおりです。
| 判定 | 件数 |
|---|---|
| KILLED | 55 |
| SURVIVED | 4 |
| EQUIVALENT | 1 |
| 合計 | 60 |
SURVIVEDした4件は、そのままにはしませんでした。
見つかった4つのテスト不足
| 対象 | 見つかった問題 |
|---|---|
| 商品登録 | 登録済み月におけるDataset分離の検証不足 |
| 店舗メモ | 複製時の作成日時の検証不足 |
| Task | 連続作成したときの並び順の検証不足 |
| 日次売上 | 2行目の保存失敗時に1行目もrollbackされることの検証不足 |
これらは、正常コードでは問題なく動いている部分でした。
しかし条件を意図的に変更すると、既存pytestでは検知できない箇所がありました。
Codexに正式テストの追加・強化を指示し、同じMutationを再適用して確認しました。
正常コード
↓
pytest GREEN
↓
Mutationを適用
↓
狙ったassertでRED
↓
Mutationをrestore
↓
pytest GREEN
この確認を行った結果、Phase 0〜6は次の状態になりました。
| 判定 | 初回 | 強化後 |
|---|---|---|
| KILLED | 55 | 59 |
| SURVIVED | 4 | 0 |
| EQUIVALENT | 1 | 1 |
| 合計 | 60 | 60 |
Phase 7〜10|CodexとCosmic Rayを組み合わせる
手動方式の60件を終えたあと、次はMutation候補の自動生成に進みました。
採用したのは Cosmic Ray 8.7.0 です。
公式ドキュメント:
Cosmic Rayは、Pythonのコードに小さな変更を加え、その変更をテストが検知できるか調べるMutation Testingツールです。
比較演算子や条件式などを自動的に変更できます。
今回の役割分担は次のようになります。
| 担当 | 主な役割 |
|---|---|
| 人間 | 監査方針・範囲・判定基準・終了条件を決める |
| Codex | 実行環境の準備、ツール実行、pytest強化、結果整理 |
| Cosmic Ray | Mutation候補の生成・実行結果の記録 |
| pytest | Mutationによる故障を検知できるか確認 |
つまり、Cosmic Rayだけで監査が完結するわけではありません。
Codexにツールの実行や結果整理を任せ、その結果を監査ルールと照合しながら進める構成です。
手動方式では自分たちが選んだ故障を中心に確認していましたが、Cosmic Rayでは、これまで候補にしていなかった変更も大量に生成されます。
ただし、生成されたMutationがすべて意味のある故障とは限りません。
そのため、まずは小さな範囲で試しました。
Phase 10A〜10Bのパイロット結果
| 判定 | 件数 |
|---|---|
| 生成・試行したMutation | 73 |
| KILLED | 54 |
| SURVIVED | 18 |
| ERROR | 1 |
| TIMEOUT | 0 |
最初からすべてKILLEDにはなりませんでした。
ただし、SURVIVEDした18件を、そのまま18件のテスト不足とは判断しませんでした。
例えば、
- 条件変更によって実際の動作が変わるのか
- その関数は現在使用されているのか
- 関連pytestの実行範囲が適切なのか
- 実行環境による影響ではないか
といった確認が必要だったためです。
関連pytestと全pytestの比較
関連pytestだけで判定してよいのか、全pytestとの比較も行いました。
| 比較項目 | 関連pytest | 全pytest |
|---|---|---|
| テスト数 | 119件 | 770件 |
| 平均実行時間 | 約5.76秒 | 約45秒 |
代表5件では判定が一致し、全pytestでのみKILLEDになるMutationは確認されませんでした。
ただし、これは比較した範囲での結果です。
すべてのMutationについて、関連pytestだけで十分だと証明したわけではありません。
Phase 11〜16|候補を増やすだけでなく、分類を見直す
Cosmic Rayの導入後は、認証・Session・権限・Datasetなどの重要な処理を中心に、監査範囲を広げていきました。
ここで作業の中心になったのは、Mutationの判定を整理することでした。
例えば、SURVIVEDしたコードがあっても、
pytestが足りない
とすぐに決めつけることはできません。
その条件が実際には使用されていない可能性もあります。
あるいは、変更しても動作が変わらないEQUIVALENT候補かもしれません。
また、関連pytestのrunnerに、本来必要なテストが含まれていないケースも考えられます。
SURVIVEDの分類
| 分類の観点 | 確認すること |
|---|---|
| 正式pytest不足 | 必要なテストが存在しない |
| assert不足 | テストはあるが故障を検知できない |
| runner範囲不足 | 別の既存pytestでは検知できる |
| EQUIVALENT候補 | 変更しても動作が変わらない |
| 未使用コード | Mutation対象が実際には利用されていない |
| 環境依存 | 実行条件の影響を受けている |
こうした候補を分類しながら、正式なテストを追加していきました。
Phase 16では商品・売上領域を再確認
Phase 16では、商品・売上を対象に199件のMutationを試行しました。
| 判定 | 件数 |
|---|---|
| Mutation | 199 |
| KILLED | 168 |
| SURVIVED | 31 |
| ERROR | 0 |
| TIMEOUT | 0 |
この段階でもSURVIVEDは残っていました。
また、途中でCodexの作業環境を引き継ぐ際、保存済みの証拠だけでは再開できない箇所もありました。
そのため、推測で途中から続行することは避けました。
必要なPhaseのテスト・候補台帳・実行結果を再構築し、確認できる状態から監査を続けました。
Phase 17〜21|業務機能ごとのpytestを強化
その後は、商品・売上だけでなく、実際の店舗業務に関係する機能も確認しました。
主な対象は次のとおりです。
| 対象領域 | 主に確認した内容 |
|---|---|
| 商品・売上 | 入力境界、複数行保存のatomic性、Dataset・年月分離 |
| Dashboard・AI | 表示期間、Dataset、AI入力境界、fallback |
| 材料発注 | 入力境界、認可、DB失敗時の応答、Dataset消失時の扱い |
例えば日次売上では、1行目の保存が成功しても、2行目で失敗した場合にデータが中途半端に残ってはいけません。
1行目 保存成功
↓
2行目 保存失敗
↓
全体をrollback
↓
不完全な売上データを残さない
という動作が必要です。
Dashboardでも、単に合計値が表示されるだけではなく、対象期間やDatasetが正しいかを確認する必要があります。
材料発注では、正常な入力だけでなく、不正な値や認可されていない操作、DB失敗時の応答も対象にしました。
Codexには、それぞれの業務機能に対してMutationを実行し、不足している正式pytestを強化するよう指示しました。
こうして、監査対象を機能ごとに広げていきました。
Phase 22〜23|店舗メモのSURVIVEDを追いかける
店舗メモでは、新しいMutationを189件試行しました。
Phase 22の結果
| 判定 | 件数 |
|---|---|
| Mutation | 189 |
| KILLED | 136 |
| SURVIVED | 53 |
53件のSURVIVEDが出ました。
ここでも、すべてを一律にテスト不足とは扱いませんでした。
その後のPhase 23では、正式なテスト強化が必要と判定したA候補49件を確認しました。
| 確認内容 | 件数 |
|---|---|
| A判定候補 | 49 |
| pytestを強化した候補 | 48 |
| runner範囲の不足が残った候補 | 1 |
店舗メモは、単にメモを保存する機能ではありません。
追加、編集、検索、削除、復元、autosaveなど複数の操作があります。
そのため、
メモが保存できた
だけでなく、
不正な操作やDB失敗時に、意図しない状態にならないか
という観点も必要でした。
また、49件すべてについて同じ検証が完了したわけではありません。
1件はrunnerの対象範囲に制約が残ったため、その事実も記録しました。
Phase 24〜25|最後はTaskの8件
最後に確認したのは、店舗メモツール内のTask機能です。
Taskでは、追加・完了・削除・並び替えなどの操作があります。
スマホから使用することも考えて、これまでUIの操作感を何度も調整してきた機能です。
Phase 24の結果
| 判定 | 件数 |
|---|---|
| Mutation | 48 |
| KILLED | 40 |
| SURVIVED | 8 |
ここで8件のSURVIVEDが確認されました。
そこでPhase 25では、A判定となった8件を個別に再確認しました。
重要だったのは、
偶然どこかのpytestが失敗しただけでは、十分な検証としないこと
です。
Codexに、変更した条件を狙ったassertが検知しているか確認してもらいました。
Phase 25の確認手順
正常コード
↓
追加pytest GREEN
↓
対象Mutationを適用
↓
狙ったassertでRED
↓
正常コードへrestore
↓
追加pytest GREEN
この手順で8件すべてを確認しました。
Phase 25の結果
| 項目 | 結果 |
|---|---|
| 対象A判定 | 8件 |
| KILLED化 | 8件 |
| 再分類 | 0件 |
| 未解決 | 0件 |
| 新規pytest | 9ケース |
Task関連のrunnerも確認しました。
80 passed
1 skipped
warnings 0
これでPhase 25の対象8件は、すべて追加pytestの狙ったassertによるREDを確認できました。
監査終了時のFinal Gate
Phase 25を終えたあと、監査全体の終了条件も確認しました。
このときの監査ブランチにおけるfull pytestは、次の結果です。
| 項目 | Phase 25終了時 |
|---|---|
| collected | 946 |
| passed | 929 |
| failed | 0 |
| skipped | 17 |
| warnings | 0 |
なお、この実行ではmigration関連の6ファイルは対象外です。
この数字は、後述する最新版mainでの実行結果とは区別する必要があります。
また、監査終了時のFinal Gate成立は、
SURVIVED 68件がすべて解消した
という意味ではありません。
ERROR 27件についても同様です。
監査対象の結果・証拠・復元状態・終了条件を確認し、定めた範囲の監査を終了したという意味です。
ここで重要だったのは、Codexが作業を終了したという報告だけで監査完了とせず、事前に決めた終了条件に沿って確認したことです。
1,286件という数字で注意したこと
今回の監査では、PhaseごとにMutationを実行しました。
しかし、同じ候補を後のPhaseで再検証した場合があります。
そのため、各Phaseの試行数を単純に足し算すると、同じMutationを二重に数える可能性があります。
そこで、監査全体の集計には重複を除いた件数を使用しました。
| 集計対象 | 件数 |
|---|---|
| 手動方式のMutation | 60 |
| Cosmic RayのユニークMutation | 1,226 |
| 合計 | 1,286 |
また、KILLED / SURVIVED / ERRORなどは保存済みの監査記録に基づく分類です。
PhaseごとのSURVIVED数や、その後の強化件数を単純に加減して、最終分類を作り直すことはしていません。
監査結果を都合よく見せるために、数字を調整したくなかったからです。
そして最後に、もう1つ問題があった
Phase 25までの監査を終えた時点で、pytestの強化は進んでいました。
ただし、ここで重要な問題が残っていました。
監査ブランチでテストを強化しただけでは、最新版mainへ反映されたことにはならない。
ということです。
Bakery Hubでは監査中も通常開発が進み、商品管理やCatalog関連の変更がmainへ追加されていました。
特にPR #79、PR #80では、商品テンプレートや商品履歴、Admin Catalogなどの変更が入っています。
そのため、古い監査ブランチをそのままmainへmergeするのは避けました。
古い監査ブランチをそのままmergeしない
今回の監査では、Mutationを入れるためにproduction codeへ一時的な変更を加えています。
当然ながら、こうした変更を本番コードへ持ち込んではいけません。
また、監査開始後にmain側のコードも進化しています。
そこでCodexへ、次の方針で出荷するよう指示しました。
古い監査ブランチ
↓
そのままmainへmergeしない
最新版origin/main
↓
新しい出荷ブランチを作成
↓
正式採用したpytestだけを移植
↓
最新版コードで再検証
↓
PR作成
今回の出荷ブランチは、
test/ship-pytest-robustness-audit
です。
PR #80反映後の origin/main を基準に作成しました。
監査で使用した古いproduction codeを上書きせず、最新版mainを基準にして正式なテストだけを移植する方法です。
mainへ持ち込んだのは正式なpytestだけ
今回の移植では、変更対象を意図的に絞りました。
新規追加したpytestファイル
| ファイル | 主な検証内容 |
|---|---|
test_phase17_product_sales_contracts.py |
商品・売上の境界、atomic性、Dataset・年月分離 |
test_phase19_dashboard_ai_contracts.py |
Dashboardの期間・Dataset、AI入力境界、fallback |
test_phase21_material_order_contracts.py |
材料発注の境界・認可 |
test_phase21_material_order_status_fallback.py |
DB失敗・Dataset消失時の応答 |
test_phase23_shop_memo_contracts.py |
店舗メモの境界・認可・autosave・JSON・DB失敗 |
test_phase25_task_contracts.py |
Task ID境界・空配列・JSON・DB状態・未認証操作 |
新規ファイルは6件です。
これに加え、既存の、
tests/test_products.py
にも正式な回帰テストとassertを差分統合しました。
合計で変更対象は7ファイルです。
すべて、
store/bakery-hub/tests/
以下のpytest関連ファイルです。
最新mainの仕様に合わせてテストを調整
ここでもう1つ大事だったのが、監査を始めた頃と最新版mainでは仕様が異なる部分があったことです。
例えば、商品名や商品価格の入力条件です。
今回の出荷では、最新版mainの正式仕様に合わせて、
| 項目 | 最新mainでの仕様 |
|---|---|
| 商品名の上限 | 100文字 |
| 商品価格の上限 | 9,990円 |
| 価格単位 | 10円単位 |
を使用しました。
また、Dataset分離の検証では、追加行用の空入力ではなく、実際の商品行を対象に確認しました。
ここで避けたかったのは、
pytestをGREENにするために、都合の悪いassertを削除する
という対応です。
Codexには、最新版mainの正式仕様に合わせて必要な差分を整理し、既存assertを安易に削除しないよう指示しました。
テストが失敗した場合は、現在の正式仕様とテストの前提を照合し、必要な変更だけを行う方針です。
最新mainを基準に、もう一度pytestを実行
監査ブランチでGREENだったからといって、そのまま出荷完了にはしませんでした。
最新のmainを基準とした出荷ブランチで、改めてpytestを確認しました。
出荷前の検証結果
| 検証項目 | 結果 |
|---|---|
| pytest collection | 1,009件 |
| collection error | 0件 |
| 新規6ファイルの関連pytest | 97 passed |
test_products.py |
77 passed |
| full pytest passed | 991 |
| failed | 0 |
| skipped | 18 |
| warnings | 9 |
full pytestの結果は、
1,009 collected
991 passed
0 failed
18 skipped
9 warnings
でした。
9件のwarningsは、SQLite migrationテストで発生するPython 3.12のdatetime adapter非推奨警告です。
また、今回の出荷検証では、実ブラウザ・実機・実PostgreSQL・並行request・本番DB・Render・実Gemini APIによる確認は行っていません。
確認できた範囲と、確認していない範囲は区別して記録しています。
PR #81を作成し、mainへmerge
最新版mainでの検証を終え、CodexにPR作成まで進めてもらいました。
PR #81
test: Bakery Hub Mutation監査で強化したpytestをmainへ反映
| 項目 | 内容 |
|---|---|
| PR | #81 |
| 出荷ブランチ | test/ship-pytest-robustness-audit |
| 変更ファイル | 7ファイル |
| 新規pytestファイル | 6ファイル |
| 変更対象 | store/bakery-hub/tests/ |
| merge先 | main |
| 結果 | Merged |
PR #81は2026年10月7日にmergeされました。
Merge commitは、
778d0c4
です。
GitHub上では2つのチェックが通過しています。
これで、監査ブランチに閉じていた正式なpytestの強化を、最新版mainへ反映できました。
ただし、これはテストコードをmainへ反映したという意味であり、本番環境での動作をすべて検証したという意味ではありません。
Codexを使った監査で何が変わったのか
今回の再監査を振り返ると、8月の手動Mutationから変わった点がいくつもあります。
8月の11件と今回の1,286件
| 比較項目 | 8月の手動検証 | 今回のCodex監査 |
|---|---|---|
| Mutation候補 | 自分で11件を選択 | 手動方式+Cosmic Ray |
| コード変更 | 自分で実施 | Codexが実行 |
| pytest実行 | 自分で確認 | Codexに実行を指示 |
| 検知力の確認 | GREEN・REDを比較 | 狙ったassertと証拠を照合 |
| 判定分類 | KILLED・SURVIVED中心 | ERROR・runner範囲なども精査 |
| 作業範囲 | 代表的な故障 | Phase 0〜25 |
| 成果の反映 | テスト強化 | 最新mainへの安全な移植まで実施 |
今回、AIを使ったことで大量のMutationを試せるようになりました。
しかし、実行件数が増えた分だけ、結果の整理や作業状態の管理も複雑になりました。
特に重要だったのは、次の3点です。
① AIがKILLEDと報告しても、根拠を確認する
CodexがKILLEDと報告した場合でも、対象Mutationと失敗したpytestを対応させて確認する必要があります。
単にHTTP 500になっただけでは、狙った仕様を検知した証拠として不十分な場合があります。
② 作業環境を失っても、推測で再開しない
長期間の監査では、セッションや作業環境を引き継ぐことがあります。
その際、候補台帳・実行ログ・コードの状態を確認できなければ、前回の続きから安全に実行できるとは限りません。
今回は、必要な証拠が不足していた箇所について、再構築を行いました。
③ 最後にmainへ反映するところまで確認する
監査ブランチでpytestが強化されても、mainへ反映されなければ通常開発では使用されません。
だからこそ、今回は最新版mainから新しい出荷ブランチを作り、正式なpytestだけを移植しました。
監査を実行することと、監査成果を安全に反映することは別の作業だと考えています。
Mutation Testingの限界も見えてきた
今回の結果を見ても、Mutation Testingだけですべてのテスト品質を証明できるわけではありません。
KILLEDになったからといって、すべての不具合を検知できるわけではありません。
SURVIVEDになったからといって、必ずテスト不足とも限りません。
ERRORについても、実行できなかった理由を調べる必要があります。
また、Cosmic Rayが生成するMutationには、実際の業務では起こりにくい変更も含まれます。
そのため、Mutationの結果を確認するだけでなく、
その条件は、Bakery Hubのどの仕様に関係するのか?
その故障を検知できなければ、実際にどんな問題が起こるのか?
という視点も必要です。
今回の監査で得られたのは、すべての不具合を防げる保証ではありません。
検知できる条件と、まだ検証の余地がある条件を、以前より広く把握できたことだと考えています。
おわりに
2026年8月、私は11件の手動Mutation Testingを実施しました。
当時は、pytestが本当に故障を検知できるかを、自分でコードを変更しながら確認しました。
それから約2か月。
Bakery Hubは機能が増え、pytestも増えました。
今回の再監査では、以前の経験をもとにCodexを活用し、監査対象を大幅に広げました。
8月
手動Mutation 11件
↓
pytestの検知力を確認
10月
Codexで手動方式のMutation 60件
↓
Cosmic Ray導入
↓
Mutation候補を拡張
↓
SURVIVED・ERRORを分類
↓
正式pytestを追加・強化
↓
狙ったassertでRED確認
↓
正常コードへrestore
↓
Phase 25終了
↓
Final Gate確認
↓
最新版mainへpytestだけ移植
↓
PR #81 merge
最終的に、重複を除いたMutationは 1,286件 になりました。
その中には、検知できたものだけでなく、SURVIVEDやERRORも残っています。
今回の監査結果を、
pytestが完璧になった証拠
とは考えていません。
むしろ、
どの条件は検知できていて、どの条件にはまだ検証の余地があるのか
を、以前より具体的に把握できたことが成果だと思います。
また、Codexを使うことで、以前の手作業だけでは現実的ではなかった規模の監査に取り組めました。
ただし、AIが大量の作業を実行できるからといって、その報告をすべて無条件に信用してよいわけではありません。
監査方針、判定基準、終了条件を決め、保存された証拠と照合する。
そして最後は、正常なコードに戻したうえで、正式なテストだけをmainへ反映する。
AIに実行を任せる範囲が広がるほど、人間側で何を確認すべきかを明確にする必要がある。
今回の5日間では、Mutation Testingだけでなく、AIを活用した開発・検証の進め方についても学ぶことができました。
まだ実務経験のない独学の段階ですが、こうした検証を積み重ねながら、安心して使えるWebアプリを作れるようになりたいと思います。
これで今回のMutation Testing再監査は一区切りです。
関連リンク
今回の商品管理改善からMutation Testing再監査、mainへの反映までを3本の記事にまとめました。
| 記事 | タイトル・リンク |
|---|---|
| 第1記事 | 🥐Bakery Hubの商品管理を作り直した|18商品テンプレート・履歴Catalog・Admin登録まで |
| 第2記事 | 🧪pytestが通るだけでは安心できない|CodexとCosmic Rayで2度目のMutation Testing |
| 第3記事 | 🧪Codexで挑んだ1,286件のMutation Testing|pytest再監査からmain反映までの5日間 |
その他の関連資料
| 分類 | リンク |
|---|---|
| 📖 2026年8月の初回Mutation Testing | 📝pytestを「事故防止台帳」として育てる 第5段階:GREENを疑い、Mutation Testingで「本当に守れているか」を検証した |
| 🔀 GitHub PR #81 | Mutation監査で強化したpytestをmainへ反映 |
| 🌐 Live Demo | Bakery Hubをブラウザで操作 |
| 💻 ソースコード | Bakery Hub |
| 📁 ポートフォリオ | Tosane Works |
Live DemoはRenderの無料環境で公開しているため、スリープ状態からの起動時に少し時間がかかる場合があります。
