0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AIにテストを書かせたら、カバレッジは上がったのに品質は上がらない理由 — “テストの良し悪し”をミューテーションテストで測る実践ガイド

0
Posted at

はじめに — 緑のバーは、安心していい合図ですか?

AIにテストを書かせると、ほんまに一瞬ですよね。

「このコードのテスト書いて」とお願いするだけで、ファイルがどんと出てくる。流すと、テストランナーが緑のバーを返してくる。カバレッジも、昨日まで40%だったのが一気に85%になっている。なんか、ちゃんと守られてる気がしてくる。

でも、ちょっとだけ立ち止まって考えてみたいんです。

その緑のバーは、「コードが正しい」合図でしょうか。それとも、「コードが動いただけ」の合図でしょうか。

ここがズレてると、けっこう怖いことが起きます。テストはあるのに、バグが本番まですり抜ける。あとで原因を追うと、テスト自体が「実行はしてるけど、何も確かめてなかった」。緑のバーに、ずっと嘘をつかれていた、みたいな状態です。

これ、私の感想だけで言ってるんじゃないんです。2026年6月に出た論文(arXiv:2606.18168「All Smoke, No Alarm」、IEEE AITest 2026採択)が、わりと衝撃的な数字を出しています。

OpenAI Codex / GitHub Copilot / Devin / Cursor / Claude Code という5つのAIエージェントが書いた 86,156件のテストファイルの変更 を、2,807リポジトリにわたって調べたところ、80.2%が「弱い、あるいは明示的なオラクル(=正解の確認)が無い」テストだった。

タイトルの「All Smoke, No Alarm(煙はあるのに、警報は鳴らない)」が、もう本質を言い切ってるなと思います。煙はもくもく出てる。でも、肝心の火災報知器は鳴らない。テストはたくさんある。でも、バグが来ても鳴ってくれない。

この記事は、その「鳴らないテスト」を見分けて、ちゃんと鳴るテストに変えていく話です。具体的にはこんな順番でいきます。

  • なぜAIが書くテストは「動くのに守らない」のか、その3つの壊れ方
  • カバレッジという数字が、なぜ「テストの良し悪し」を測れないのか
  • テストの良し悪しを正面から測る方法 = ミューテーションテスト
  • AIにテストを書かせるときの、正しい順番とプロンプト3本
  • 落とし穴と、安全に使うための線引き

AI開発にまだ慣れてない方でも置いていかれないように、用語は出てくるたびに噛み砕いていきます。コードもPythonとTypeScriptで、そのまま試せる形で置いておきますね。


まず、言葉をそろえましょう(知らない前提でいきます)

いきなり「ミューテーションが」「オラクルが」と言われても、しんどいですよね。なので、最初に登場人物を整理します。全部、火災報知器のたとえで通します。

  • テスト(ユニットテスト):あるコードに値を入れて、出てきた結果が正しいかを自動でチェックする小さなプログラム。火災報知器そのもの、と思ってください。
  • アサーション(assertion):テストの中の「ここがこうなってるはずだ」と断言する1行。assert 結果 == 100 みたいなやつです。これが火災報知器の“鳴る部分” です。アサーションが無いテストは、センサーだけあって音が鳴らない報知器。
  • カバレッジ(coverage):テストを走らせたとき、製品コードの何行(何分岐)が実行されたかの割合。「煙が部屋に届いたか」だけを数えてる イメージです。届いたかどうかと、警報が鳴ったかどうかは、別の話ですよね。
  • オラクル(oracle):そのテストにとっての「正解は何か」を知っている人、または仕組みのこと。テストの神様みたいな響きですが、要は 「期待値はこれだ、と決める根拠」 です。apply_discount(1000, 0.2) の正解は 800 だ、と決めるのがオラクル。ここが今日いちばん大事な言葉です。
  • ミュータント(mutant):コードにわざと仕込む、小さなバグ。a + ba - b に変える、>>= に変える、みたいな1文字レベルの改変です。
  • ミューテーションテスト:そのミュータント(わざとのバグ)を入れたとき、テストが落ちてくれるかを確かめる手法。落ちたら「バグを捕まえた=kill(殺した)」、落ちなかったら「見逃した=survived(生き残った)」。
  • ミューテーションスコア殺せたミュータント ÷ 入れたミュータント の割合。これが「火災報知器、ちゃんと鳴りますか?」のテスト です。

ここで一個だけ、腹に落としてほしいことがあります。

コードが実行されること(カバレッジ)と、間違いを検知できること(アサーション)は、全然ちがう。

煙が部屋に入ってきても、報知器が鳴らなきゃ意味がない。カバレッジ85%は「煙が85%の部屋に届いた」だけで、「火事のとき鳴る」保証はどこにも無いんです。


AIのテストが「動くのに守らない」3つの壊れ方

では、AIが書くテストはどう壊れるのか。私が見てきた限り、だいたい3パターンに分かれます。

壊れ方①:アサーションが無い、または弱い

いちばん多いのがこれです。コードは呼ぶ。でも、結果を断言しない。

実はこれ、AI以前からある古い話で、マーチン・ファウラーが「Assertion Free Testing(アサーションの無いテスト)」という有名なエッセイで書いています。あるプロジェクトが「全public関数にJUnitテストがあります」と緑のバーを誇らしげに見せたのに、テストの中にアサーションが1つも無かった、という逸話です。アサーションが無ければ、テストは例外で落ちない限り永遠に緑。カバレッジ100%だって作れてしまう。

# 弱いテスト:呼ぶだけ。何も断言していない(=鳴らない報知器)
def test_apply_discount_weak():
    result = apply_discount(1000, 0.2)
    assert result is not None   # None じゃなければ何でも通る

apply_discount800 を返そうが 7 を返そうが、このテストは通ります。煙センサーはあるのに、音を鳴らす配線がつながってない状態です。

# 強いテスト:何が正しいかを断言している(=鳴る報知器)
def test_apply_discount_strong():
    assert apply_discount(1000, 0.2) == 800
    assert apply_discount(0, 0.5) == 0
    assert apply_discount(1000, 0) == 1000

壊れ方②:トートロジー(実装を、そのまま正解にしてしまう)

これがいちばん厄介で、見た目はちゃんとしてるのに中身が空っぽ、というやつです。

# トートロジー:実装そのものを期待値に使っている
def test_calc_total_tautology():
    cart = [{"price": 100, "qty": 3}]
    expected = calc_total(cart)        # ← テスト対象を呼んで「正解」にしている
    assert calc_total(cart) == expected

これ、絶対に落ちません。だって「calc_total の結果は calc_total の結果と等しい」と言ってるだけですから。仮に calc_total に「数量を掛け忘れる」というバグがあっても、バグった答えがそのまま「正解」になる。バグごと、まるっと固定してしまう んです。

なんでAIがこれをやりがちか。理由はシンプルで、AIは「仕様(こうあるべき)」じゃなくて「コード(いま、こう動いている)」を見てテストを書くから です。目の前のコードの挙動を観察して、それをそのまま期待値にする。だからコードが間違っていても、間違いごとコピーしてしまう。

実際、2024年末の研究(arXiv:2412.14137)でも、LLMベースのテスト生成ツールのオラクルが「誤った挙動をそのまま是認したり、バグを暴くテストの方を棄却したりする」傾向が報告されています。正解を知らないまま正解を書こうとすると、こうなるんですね。

壊れ方③:ハッピーパスしか通らない

3つめは、正常系だけ書いて、異常系・境界値を書かないパターンです。

# ハッピーパスだけ:気持ちのいい入力しか試していない
def test_divide_happy():
    assert divide(10, 2) == 5

divide(10, 0)(ゼロ割り)は? マイナスは? 文字列が来たら? ——バグって、だいたい「気持ちのいい入力」の外側に潜んでます。境界(0、空配列、最大値、最小値)と異常(不正な型、None、例外)こそ報知器を置くべき場所なのに、AIは頼まないと、たいてい真ん中の安全地帯しかテストしてくれません。

この3つに共通するのは、「コードを実行はしている(だからカバレッジは上がる)」のに、「正しさは確かめていない(だから守ってはいない)」 という一点です。


カバレッジが「品質」を測れない、構造的な理由

ここで、さっきの違和感を正面から言語化します。

カバレッジは「実行された行」を数える指標です。アサーションが強いか弱いかは、1ミリも見ていません。 だから、弱いテストでもカバレッジは平気で上がる。むしろAIは「カバレッジを上げてください」と言われると、アサーションを増やすんじゃなくて「とにかくコードを通る入力」を増やしがちです。これが、数字だけ立派な“飾りのテスト”が生まれる仕組みです。

メタ(Facebook)のエンジニアリングブログ(2025年9月、ミューテーションテストの大規模実用化の記事)も、まさにここを突いています。

構造的なカバレッジ基準(statement coverage や branch coverage)は、コードの行が実行されたかどうかしか示さない。行が実行されてもバグを検知できないことがある。

つまり、こういう絵が普通に起きます。

  • カバレッジ 95% / でも実際にバグを捕まえる力(ミューテーションスコア)は 30%

数字は95点なのに、実力は30点。報知器が95%の部屋にあるのに、火をつけても3割しか鳴らない。これを「品質保証できてます」と言うのは、ちょっと無理がありますよね。

誤解しないでほしいのは、カバレッジが無意味なわけじゃない ということです。カバレッジは「まだ一度も触られてない場所」を教えてくれる、最低限の衛生チェックとしては有効です。ファウラーも補足で「アサーションが無くても、null参照みたいな実行時エラーは見つかることはある」と言っています。

ただ、カバレッジは 品質の“下限”を見るもの であって、品質の“高さ”を保証するものじゃない。ここを混同したまま「カバレッジ80%達成、テスト完了」とやると、静かに事故ります。


本命:ミューテーションテスト — わざとバグを入れて、報知器が鳴るか試す

じゃあ、テストの「良し悪し」をどう測るのか。ここで主役の登場です。ミューテーションテスト です。

考え方は、拍子抜けするくらいシンプルです。

  1. 製品コードに、小さなバグ(ミュータント)をわざと1個入れる。例:a + ba - b
  2. その状態でテストを全部流す。
  3. どれかのテストが落ちたら、そのバグは捕まえられた=kill
  4. 全部のテストが通ってしまったら、バグは見逃された=survived(生き残り)
  5. これを何十・何百ものミュータントで繰り返して、kill ÷ 全体ミューテーションスコア を出す。

要は、「火災報知器の点検で、わざと煙を焚いてみる」 のと同じです。鳴れば合格、鳴らなければ、その報知器(テスト)は飾りだったとバレる。だからミューテーションテストのことを、私は「テストのためのテスト」と呼んでいます。

メタのブログも、ミューテーションテストを「(数十年の研究が一貫して示してきた)最も強力なテストの形」と表現していました。同時に「ミューテーションテストはそれ単体では成立しない。先にテストが存在していないと始まらない」とも。あくまで 既にあるテストの強さを測って、弱いアサーションを炙り出す装置 なんですね。

道具(2026年時点)

言語 ツール ひとこと
Python mutmut mutmut run で実行、mutmut browse で生き残りを確認。pytestと相性が良い
JS / TS / .NET Stryker ミューテーション種が豊富、Jest / Vitest 対応、変更分だけ回すincrementalモードあり
Java PIT JVM系の定番

実際にやってみる(Python / mutmut)

さっきの「弱いテスト」に、mutmutをかけてみる想定で見てみましょう。対象はこんなコードだとします。

# shop.py
def apply_discount(price: int, rate: float) -> int:
    if rate < 0 or rate > 1:
        raise ValueError("rate must be between 0 and 1")
    return int(price - price * rate)

mutmutを動かします。

# インストールして、対象とテストコマンドを指定して実行
pip install mutmut
mutmut run --paths-to-mutate shop.py --runner "pytest -q"

# 生き残ったミュータント(=テストが見逃したバグ)を一覧で見る
mutmut results
mutmut browse

もしテストが「壊れ方①」の弱いやつ(assert result is not None)だけだと、こんな報告が返ってきます。

survived: rate < 0  →  rate <= 0  に変えても、テストは全部通った
survived: price - price * rate  →  price + price * rate に変えても通った

「鳴らへんかったで」と教えてくれてるわけです。ここで初めて、自分のテストが報知器として機能してなかったと分かる。で、アサーションを足して、もう一度回す。

def test_apply_discount_kills_mutants():
    assert apply_discount(1000, 0.2) == 800      # 「-」を「+」に変えたら 1200 になって落ちる→kill
    assert apply_discount(1000, 0) == 1000
    # 境界:rate がちょうど 0 / 1 は許可、その外は例外
    assert apply_discount(500, 1) == 0
    import pytest
    with pytest.raises(ValueError):
        apply_discount(500, 1.5)                  # 「>」を「>=」に変えたら例外が出なくなって落ちる→kill

再実行してミューテーションスコアが上がれば、それは「報知器がちゃんと鳴るようになった」という、目に見える前進です。カバレッジと違って、ごまかしが効きません。

JS / TS なら Stryker

TypeScriptでも考え方は同じです。設定ファイルを置いて回すだけ。

// stryker.conf.js
/** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */
module.exports = {
  testRunner: "vitest",
  coverageAnalysis: "perTest",
  mutate: ["src/**/*.ts", "!src/**/*.test.ts"],
  thresholds: { high: 80, low: 60, break: 50 }, // スコアが50%未満ならCIを落とす
};
npx stryker run
# → killed / survived / no coverage を色分けしたレポートが出る

thresholds.break を決めておくと、「ミューテーションスコアが一定を下回ったらビルドを失敗させる」ができます。カバレッジゲートの、ひとつ上の世界ですね。


テストオラクル問題 — ここだけは、人間が握る

さて、ここまで来ると、ひとつの壁にぶつかります。

ミュータントを入れて回すのは機械が得意。アサーションの“形”を書くのもAIが得意。でも「apply_discount(1000, 0.2) の正解は本当に 800 なのか?」を決めるのは、誰の仕事でしょう。

これが、ソフトウェアテストの世界で昔から「テストオラクル問題」と呼ばれてきた、いちばん難しいところです。テストの仕組み(How)はいくらでも自動化できる。でも「何が正しい答えなのか(What / Why)」は、仕様や意図を知っている人間にしか決められない。

ここでAIに「正解も推測しといて」とやると、壊れ方②のトートロジーに逆戻りです。AIは目の前のコードを見て「たぶんこれが正解」と埋めるので、コードが間違ってたら間違いが正解になる。だから、

オラクル(正解の根拠)は人間が与える。テストの仕組みはAIに書かせる。

この分担が、今日いちばん持って帰ってほしい一行です。表にするとこうなります。

工程 人間(What / Why) AI(How)
守りたい挙動を決める ◎ 仕様・意図・正解を決める △ 候補出しの補助
境界値・異常系の洗い出し ◎ 抜けの最終判断 ○ 候補を大量に出す
テストコードを書く △ レビュー ◎ 仕組みを書く
アサーションの強さ点検 ◎ 何を検証してないか判断 ○ 弱い箇所の指摘
ミューテーションで採点 ○ しきい値を決める ◎ 実行・集計
生き残りバグの解釈 ◎ 直す/等価と判断 ○ 説明の下書き

AIは優秀な“テスト職人”です。でも、何を守るべきかの設計図は、人間が描く。職人に設計まで丸投げすると、立派だけど誰も住めない家が建ってしまう、という感じですね。


AIにテストを書かせる「正しい順番」=計測駆動の品質ループ

役割分担が決まったら、あとは順番です。私はこれを「計測駆動の品質ループ」と呼んでいます。5ステップです。

  1. 人間が、守りたい挙動と境界・異常系を先に決める。 ここがオラクルの種。「割引率は0〜1、それ以外は例外」「空カートは0円」みたいに、コードを見る前に言語化する。
  2. AIにテストを書かせる。 ただし「実装からではなく、この仕様から書いて」と渡す。
  3. アサーションの強さをレビューする。 「このテスト、何を検証してない?」をAIにも人間にも問う。
  4. ミューテーションテストで採点する。 survived(生き残り)が出たら、そこが報知器の穴。
  5. CIゲートを、カバレッジじゃなくミューテーションスコアにする。 ただし全部に回すと重いので、変更があったファイルや重要モジュールだけ に絞る。

ステップ5を、GitHub Actionsで雑に書くとこんな感じです。

# .github/workflows/mutation-gate.yml
name: mutation-gate
on: [pull_request]

jobs:
  mutation:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: actions/setup-python@v5
        with: { python-version: "3.12" }
      - run: pip install pytest mutmut

      # 変更があった .py だけをミューテーション対象にする(全体は重いので絞る)
      - name: Run mutation testing on changed files
        run: |
          CHANGED=$(git diff --name-only origin/${{ github.base_ref }}... \
            | grep -E '\.py$' | grep -v '_test\.py$' || true)
          if [ -z "$CHANGED" ]; then echo "no python changes"; exit 0; fi
          echo "mutating: $CHANGED"
          mutmut run --paths-to-mutate "$CHANGED" --runner "pytest -q"

      # 生き残りが多すぎたら落とす(しきい値は人間が決める)
      - name: Check survivors
        run: |
          mutmut results
          SURVIVED=$(mutmut result-ids survived | wc -w | tr -d ' ')
          echo "survived mutants: $SURVIVED"
          if [ "$SURVIVED" -gt 5 ]; then
            echo "::error::Too many survived mutants ($SURVIVED). Strengthen your assertions."
            exit 1
          fi

ポイントは、しきい値(いくつ生き残ったら落とすか)は人間が決める ことと、変更分だけに絞ってコストを抑える ことです。いきなり全社のコードに100%を求めると、計算時間で死にます。まずは「お金・安全・データに関わる重要モジュール」から始めるのが現実的です。


そのまま使えるプロンプト例3本

ここからは、AIに頼むときの実物です。3本とも、最終判断は人間がする 前提で作っています。コピペして、ダミー部分を自分のコードに置き換えてください。

プロンプト①:境界値・異常系の洗い出し(コードからではなく、仕様から)

あなたはテスト設計のレビュアーです。
以下の「関数の仕様」だけを根拠に、テストすべきケースを洗い出してください。
※実装コードは見ずに、仕様から考えること。

# 仕様
apply_discount(price, rate):
  - price は 0 以上の整数(円)
  - rate は 0.0〜1.0 の割合
  - 戻り値は割引後の金額(整数、端数は切り捨て)
  - rate が範囲外なら ValueError

# 出力形式(表)
| 分類(正常/境界/異常) | 入力 | 期待値または期待例外 | このケースで守りたい挙動 |

正常系だけでなく、境界(0, 1, 端数が出る値)と
異常(範囲外, 負の価格, 型違い)を必ず含めること。
抜けがありそうな観点も最後に箇条書きで指摘してください。

仕様から考えさせるのが肝です。これで、壊れ方③(ハッピーパスだけ)をかなり潰せます。

プロンプト②:オラクルを明示したテスト生成(実装のコピー禁止)

次の仕様とテストケース表をもとに、pytest のテストを書いてください。

# 厳守ルール
- 期待値は、私が表で与えた値だけを使うこと。
  テスト対象の関数を呼んで、その結果を期待値にしないこと(トートロジー禁止)。
- 各 assert の横に、「この assert がどのバグを捕まえるか」をコメントで書くこと。
- 例外ケースは pytest.raises で明示すること。
- マジックナンバーには意味をコメントで添えること。

# 仕様
(プロンプト①の仕様を貼る)

# テストケース表
(プロンプト①の出力を貼る)

「実装を呼んで期待値にするな」と明示することで、壊れ方②(トートロジー)を構造的に防ぎます。「各assertがどのバグを捕まえるか書け」と言うと、アサーションが自然と強くなります。

プロンプト③:テスト品質レビュー(何を検証してないか/生き残りの埋め方)

以下のテストコードと、ミューテーションテストで「生き残ったミュータント」の一覧を渡します。
あなたの仕事は、テストの“穴”を見つけることです。

# やってほしいこと
1. 各生き残りミュータントについて、なぜ今のテストが捕まえられないかを説明する。
2. それを捕まえるための追加 assert を提案する(期待値の根拠も書く)。
3. 「等価ミュータント(挙動が本当に変わらず、殺せないのが正しいもの)」の
   可能性があるものは、そう指摘して人間の確認に回す。
   → 確信が持てないものは断定せず「要確認」と書くこと。

# テストコード
(ここに貼る)

# 生き残ったミュータント
(mutmut results / stryker のレポートを貼る)

ここでも、AIに「断定させない」のが大事です。等価ミュータントかどうかは人間が決める。AIは候補と理由を出す係に徹してもらいます。


落とし穴と、ミューテーションテスト自体の注意点

便利な道具ほど、雑に使うと事故ります。よくある落とし穴を6つと、ミューテーションテスト固有の注意を置いておきます。

# 落とし穴 どうなるか
1 カバレッジ100%で安心する 実行されただけ。鳴らない報知器が満室になる
2 アサーション無しテストを量産 緑のバーが嘘をつき始める
3 実装をコピーした期待値(トートロジー) バグごと固定。永遠に落ちない
4 ハッピーパスしか書かない 境界・異常という“バグの巣”が無防備
5 オラクル(正解)までAIに丸投げ 間違いが正解になる
6 ミューテーションスコア100%を盲信 100%でもバグ0の保証ではない

そして、ミューテーションテストにも弱点があります。ここを知らずに使うと、逆に振り回されます。

  • 等価ミュータント(equivalent mutant):コードを変えたのに、挙動がまったく変わらないミュータントがあります(例:絶対に通らない分岐の中の変更)。これは「殺せない」のが正しいのに、レポート上は survived として残る。全部を0にしようとすると、この幻のバグ退治に時間を溶かします。 「これは等価」と人間が判断して除外していい。
  • 計算コストが高い:ミュータントを何百個も作って毎回テストを回すので、重い。だから 変更分・重要モジュールに絞る のが鉄則です。全コードに毎回フルでかけるものではありません。
  • スコアは万能じゃない:ミューテーションスコア80〜90%台はとても良い目安ですが、100%でもバグが無い証明にはなりません。プロパティベーステストや統合テスト、人間のレビューと組み合わせるものです。

撤退ラインも決めておきましょう。

  1. スコアが頭打ちになったら、追うのをやめる。 90%超を95%にする労力より、別モジュールの50%を80%にする方が価値が高いことが多いです。
  2. 等価ミュータントだらけのモジュールは、ミューテーション対象から外す。 無理に追わない。
  3. 重要度が低いコードは、カバレッジの最低限だけで十分。 全部に同じ厳しさを求めない。

安全に使うために — テストデータと不可逆操作

最後に、安全の話を少しだけ。テストまわりは、地味に事故が起きやすい場所です。

  • テストデータに、本物の個人情報や秘密情報を入れない。 AIにテストを書かせるとき、実データをそのまま貼ると「AIに渡す=外に出す」ことになります。氏名・メール・APIキー・本番のレコードは、必ずダミー(user@example.comtest-token-xxxx など)に置き換える。
  • テストが、不可逆な操作を本物に向けて叩かないようにする。 本番DBへの書き込み、課金、メール送信、データ削除——こういう「戻せない操作」は、テストではモックやサンドボックスに逃がす。AIが生成したテストが、うっかり本番のエンドポイントを叩いていないか、人間が必ず確認する。
  • 外部から来たテキストは“データ”として扱う。 Issueやログをそのままプロンプトに混ぜると、そこに紛れた指示にAIが反応することがあります(プロンプトインジェクション)。外部入力は命令ではなくデータとして囲って渡す。

このあたりは、テストの良し悪し以前の「戸締まり」です。良いテストを書く前に、鍵を閉めておきましょう。


おわりに — 緑のバーを、明日の自分への約束に変える

ここまでお付き合いいただいて、ありがとうございます。

最後に、ひとつだけ。私がこのテーマを大事だと思う理由は、テストって結局「未来の自分との約束」だからなんです。

弱いテストは、緑のバーで「大丈夫だよ」と言ってくれる。でもそれは、何も確かめていない“空っぽの安心”です。半年後、本番でバグが出たとき、その緑のバーは何も守ってくれない。むしろ「テストあったのに、なんで」と、過去の自分を責めたくなる。

でも、ここで過去の自分を責めるのは、ちょっと違うと思っていて。弱いテストを書いてしまったのは、ただ「アサーションの強さ」という見方を、まだ持ってなかっただけです。

強いテストは、逆です。バグが入り込もうとした瞬間に、報知器みたいに鳴ってくれる。「ここ、変わってるで」と教えてくれる。それは、未来の自分への置き手紙であり、「あの時ちゃんと鳴るようにしといてくれて、あざっす」 と言える贈り物になる。責める道具じゃなくて、思いやりの道具なんです。

そして、ちゃんと鳴るテスト群は、放っておいても消えません。コードを書き換えるたびに、何度でも守ってくれる。これは積み上がっていく 資産 です。書くのはAI(How)でいい。でも「何を守るか(What / Why)」を決める力は、AIに奪われない。むしろAI時代に、いちばん値上がりするスキルだと思います。

なので、もし今日ひとつだけ試すなら、これを。

  1. いちばん大事な関数を1つ選ぶ(お金・データ・安全に関わるやつ)。
  2. mutmut か Stryker を1回だけ回してみる。 スコアが想像より低くて、たぶん驚きます。
  3. 生き残ったミュータントを1個選んで、それを殺すアサーションを1行足す。
  4. CIに、変更分だけのミューテーションチェックを1本入れる。

たった1行のアサーションが、半年後のあなたを救うかもしれません。緑のバーを、ただの色から、ちゃんと意味のある約束に変えていきましょう。

それでは、今日もご安全に。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?