はじめに - この記事で何が起きるか
この記事を読み終わる頃、あなたはこう思うでしょう。
「テストケース作成に何日もかけていた自分は一体何だったのか」と。
今回、私はClaude Code Skillを使って:
- 140,000,000ケースのテスト組み合わせを104ケースに削減(99.9999%削減)
- テスト実行時間を104時間から2秒に短縮(170,000倍高速化)
- 96%の命令カバレッジと87%の分岐カバレッジを達成
しました。
はい、タイポではありません。1億4000万です。
「そんなバカな」と思ったあなた。その感覚は正しい。でも事実です。
この記事では、Pairwise法(All-Pairs法)とClaude Code Skillの組み合わせがどれだけヤバいのか、実際のコードと数値で証明します。
前提:組み合わせ爆発という地獄
エンタープライズ開発でこんな仕様を見たことはありませんか?
「割引率計算システム」
- 会員ランク: 5種類(Bronze, Silver, Gold, Platinum, Diamond)
- 商品カテゴリ: 10種類(Electronics, Fashion, Food...)
- 購入金額: 5段階(~1000円、1001-5000円...)
- キャンペーンコード: 1000種類(000-999)
- 曜日: 7種類
- 時間帯: 4種類
- 支払い方法: 5種類
- 配送方法: 4種類
全組み合わせは?
5 × 10 × 5 × 1000 × 7 × 4 × 5 × 4 = 140,000,000ケース
1億4000万通りです。
「全部テストしろ」と言われたQAエンジニアの顔を想像してください。
1ケース2msで実行できたとしても:
- テスト実行時間: 80時間
- コンパイル時間: 23時間
- ファイルサイズ: 6.7GB
- 合計: 4.3日
修正 → テスト実行 → 結果確認のサイクルが4.3日。
これが現実です。地獄です。
解決策1:サンプリング(ドメイン知識による賢い削減)
実装を見てみましょう。
private double getCampaignDiscount(int firstDigit) {
return switch (firstDigit) {
case 0 -> 0.20; // 0xx: 特別キャンペーン
case 1 -> 0.15; // 1xx: プレミアムキャンペーン
case 2 -> 0.10; // 2xx: 通常キャンペーン
case 3 -> 0.08;
case 4 -> 0.06;
case 5 -> 0.05;
case 6 -> 0.04;
case 7 -> 0.03;
case 8 -> 0.02;
case 9 -> 0.01;
default -> 0.00;
};
}
お気づきですか?
キャンペーンコードは最初の1桁しか見ていない。
つまり、「023」も「056」も「099」も全て同じ「0xx」として扱われます。
ならば、1000個全部テストする必要はない。代表値10個(000, 100, 200, ..., 900)で十分です。
140,000,000ケース → 1,400,000ケース(99.0%削減)
これがサンプリングです。ドメイン知識を使った賢い削減。
でも、140万ケースでもまだ地獄です(テスト実行62分)。
解決策2:Pairwise法(組み合わせ最適化の魔法)
ここで登場するのがPairwise法です。
研究によると、ソフトウェアのバグの70-90%は2つの因子の相互作用で発生します。
「会員ランクがGold かつ 商品カテゴリがElectronics」
「時間帯が深夜 かつ 配送方法が店舗受取」
こういうペアの組み合わせさえ全てカバーすれば、ほとんどのバグを検出できます。
Pairwise法は、全ての因子ペアを少なくとも1回はカバーする最小の組み合わせを生成します。
結果:
1,400,000ケース → 104ケース(99.99%削減)
たった104ケースで全因子ペアをカバー。
これにより:
- テスト実行時間: 0.21秒
- コンパイル時間: 1秒
- ファイルサイズ: 5KB
- 合計: 2.2秒
修正 → テスト実行 → 結果確認のサイクルが2秒。
4.3日が2秒になりました。
Claude Code Skillという革命
「理論は分かった。でも実装が面倒でしょ?」
いいえ。
Claude Code Skillを使えば、自然言語で指示するだけです。
私がやったこと:
ユーザー: 「Pairwiseテストを生成して」
これだけ。
Claude Codeが:
- Javaソースコードを解析
- @pairwise DSLアノテーションを読み取り
- allpairspyライブラリでPairwise組み合わせを生成
- JUnit 5のパラメータ化テストを生成
- ビジネスロジックを理解してアサーションを実装
全自動でやってくれます。
自作DSLとOSSライブラリの融合
ここが凄いところです。
Claude Code Skillは:
- 自作のDSL(@pairwise, @pairwise-sample, @pairwise-names)を解釈し
- 既存のOSSライブラリ(allpairspy)を呼び出し
- LLMの理解力でビジネスロジックに基づくテストコードを生成
この3つをシームレスに統合します。
自作DSLの例
/**
* @pairwise 0,1,2,3,4
* @pairwise-names Bronze,Silver,Gold,Platinum,Diamond
*/
private final int memberRank;
/**
* @pairwise-sample 000,100,200,300,400,500,600,700,800,900
*/
private final String campaignCode;
これだけで:
- Pythonスクリプトがアノテーションを解析
- allpairspyが組み合わせ最適化
- LLMがテストロジックを実装
人間がやることは、DSLでパラメータを定義するだけ。
責務分離の美学
このSkillの設計が素晴らしいのは、責務分離が明確なことです:
| 担当 | 責務 |
|---|---|
| Pythonスクリプト | Pairwise Fixture生成のみ |
| LLM(Claude Code) | テストロジックの実装 |
なぜこの分離が重要か?
Pythonスクリプトは:
- 高速(allpairspyは最適化済み)
- 決定論的(毎回同じ組み合わせ)
- デバッグ可能(単純なアルゴリズム)
LLMは:
- ビジネスロジックを理解
- 適切なアサーションを生成
- エッジケースを考慮
適材適所。これがSkillの本質です。
実装の旅:ハマったポイントと解決策
実装は順風満帆ではありませんでした。いくつかの壁がありました。
壁1:型の悪夢
最初の実装では、全パラメータがObject型になり:
error: incompatible types: Object cannot be converted to int
原因:型情報が失われていた。
解決:JavaAnalyzerで(factors_dict, field_types_dict, target_class_name)を返すように修正。
壁2:Stringが数値に変換される地獄
campaignCode(String型)の"000", "100"が数値0, 100に変換され:
ArgumentConversionException: Cannot convert argument
原因:_parse_pairwise_tag()がフィールド型を考慮していなかった。
解決:
def _parse_pairwise_tag(self, javadoc: str, tag_name: str, field_type: str) -> List:
# If field type is String, keep as string (don't convert to int)
if field_type == 'String':
return values
# Try to convert to int if all values are numeric (for int/Integer types)
if all(v.isdigit() for v in values):
return [int(v) for v in values]
型を尊重する。プログラミングの基本です。
壁3:責務の曖昧さ
当初、Pythonスクリプトがテストロジックも生成しようとしていました。
ユーザーから痛烈な指摘:
「ここでスキルって言っているのは、Pythonスクリプトじゃない!
SKILL.mdにLLMへの指示としてちゃんとTesteeに対応するTestを書くように指示して!
ペアを抽出するのと、それをFixtureとしてテストロジックを書くのは別の話でしょ?」
完全に正しい。
解決:skill.mdに明記:
## IMPORTANT: After Pairwise Fixture Generation
**YOU (the LLM) MUST implement the actual test logic!**
The Python script only generates:
- Pairwise test data combinations (fixtures)
- Parameterized test method skeleton
- TODO comments as placeholders
### Your Responsibilities:
1. Read the test target class
2. Understand the business logic
3. Implement test logic in the TODO section
責務を明確にする。これがチーム開発の鉄則です。
カバレッジの衝撃
実行結果:
| 指標 | カバレッジ |
|---|---|
| 命令カバレッジ | 96.0% (412/429) |
| 分岐カバレッジ | 87.0% (95/108) |
たった104ケースで96%の命令カバレッジ。
これは偶然ではありません。Pairwise法が数学的に保証しているからです。
削減効果の全貌
2段階削減の内訳
第1段階(サンプリング):
140,000,000ケース → 1,400,000ケース(99.0%削減)
第2段階(Pairwise法):
1,400,000ケース → 104ケース(99.99%削減)
合計削減率: 99.9999%
削減倍率: 1,346,154倍
時間削減効果
| ケース数 | 実行時間 | ファイルサイズ |
|---|---|---|
| 140,000,000 | 104時間(4.3日) | 6.7GB |
| 1,400,000 | 62分 | 67MB |
| 104 | 2.2秒 | 5KB |
実用上の影響
開発サイクル:
- 理論値: 4.3日/サイクル → 開発停滞
- サンプリング後: 62分/サイクル → 1日数回
- Pairwise法: 2秒/サイクル → 1日数百回
CI/CD:
- GitHub Actions無料枠(月2,000分)の場合:
- 理論値: 月0.3回しか実行できない
- サンプリング後: 月32回
- Pairwise法: 実質無制限
生産性:
エンジニアの時給を5,000円とすると:
- 理論値での待ち時間: 104時間 × 5,000円 = 520,000円/回
- Pairwise法: ほぼゼロ
1回のテストサイクルで50万円のコスト削減。
もうエンジニアもQAも要らない?
ここまで読んで、こう思ったかもしれません。
「これ、もう人間要らないのでは?」
半分正解、半分不正解です。
人間が不要になったこと
- テストケースの手動作成
- 組み合わせ表のExcel管理
- 全パターンテストの実行
- 単純なアサーションの実装
これらは完全に自動化できます。
Claude Code Skillに任せればいい。
人間が絶対に必要なこと
-
ドメイン知識によるサンプリング判断
- 「キャンペーンコードは最初の1桁だけ見ている」という実装理解
- これがなければ1億4000万ケースのまま
-
DSLの設計
- どの因子をどう表現するか
- @pairwise vs @pairwise-sample の使い分け
-
ビジネスロジックの理解
- 「割引率は0.0-0.7の範囲であるべき」という仕様理解
- これがないと適切なアサーションが書けない
人間の役割は、単純作業から戦略的判断にシフトします。
結論:テスト戦略の新時代
この記事で示したのは:
- サンプリング(ドメイン知識)+ Pairwise法(組み合わせ最適化) で1億4000万ケースを104ケースに削減
- Claude Code Skill で全プロセスを自動化
- 自作DSL + OSSライブラリ + LLM のシームレスな統合
- 責務分離 による保守性の確保
- 96%カバレッジ という実証結果
これは単なる「テスト削減」の話ではありません。
テスト戦略そのものの再定義です。
あなたが今日からできること
- プロジェクトの組み合わせ爆発を特定する
- 実装を理解してサンプリング可能な因子を見つける
- @pairwise DSLでパラメータを定義する
- Claude Code Skillに「Pairwiseテストを生成して」と言う
以上。
最後に
「テストケースが多すぎて困っている」
「組み合わせテストに何日もかかっている」
「カバレッジが上がらない」
そんな悩みを持つ全てのエンジニア・QAに伝えたい。
もう、その苦労は不要です。
Claude Code Skillと Pairwise法があれば:
- 1億4000万ケースが104ケースになる
- 4.3日が2秒になる
- 手動作成がチャットだけになる
私がGitHubで公開している実装を見てください。
全てのコード、DSL、Skillが含まれています。
そして試してください。
テスト戦略の新時代へようこそ。
参考情報
- プロジェクトリポジトリ: GitHub
- 使用技術:
- Java 17
- JUnit 5
- JaCoCo 0.8.11
- allpairspy 2.5.1
- Claude Code Skill
- カバレッジ結果: 96%命令、87%分岐
- 削減率: 99.9999%
- 高速化: 170,000倍
学術的参考文献
Pairwise法(組み合わせテスト)の理論的基盤:
-
NIST SP 800-142: "Practical Combinatorial Testing"
- Authors: D. Richard Kuhn, Raghu N. Kacker, Yu Lei
- Publisher: National Institute of Standards and Technology (NIST)
- Year: October 2010
- URL: https://csrc.nist.gov/publications/detail/sp/800-142/final
- Note: Pairwise法の包括的なチュートリアル。ソフトウェア保証のための組み合わせテスト手法を解説。
-
"Software Fault Interactions and Implications for Software Testing"
- Authors: D. Richard Kuhn, Dolores R. Wallace, Albert M. Gallo Jr.
- Journal: IEEE Transactions on Software Engineering
- Year: 2004
- Note: ソフトウェアの欠陥の70-90%が2つ以下のパラメータ相互作用によって引き起こされるという統計的根拠を示した重要論文。
-
NIST Combinatorial Testing Project
- URL: https://csrc.nist.gov/projects/automated-combinatorial-testing-for-software
- Tools: ACTS (Advanced Combinatorial Testing System)
- Note: NIST主導の組み合わせテスト研究プロジェクト。4,500人以上のユーザーが利用する無料ツールを提供。
-
"ACTS: A Combinatorial Test Generation Tool"
- Authors: L. Yu, Y. Lei, R.N. Kacker, D.R. Kuhn
- Conference: IEEE Sixth International Conference on Software Testing, Verification and Validation (ICST 2013)
- Award: Most Influential Paper Award at ICST 2023
- Note: 実用的な組み合わせテスト生成ツールに関する論文。
-
allpairspy - Python Implementation
- Library: allpairspy 2.5.1
- Implementation: Microsoft PICT (Pairwise Independent Combinatorial Testing) アルゴリズムのPython実装
- PyPI: https://pypi.org/project/allpairspy/
- Reference: http://www.pairwise.org
これらの研究により、Pairwise法が単なる経験則ではなく、数学的・統計的根拠に基づく実証済みの手法であることが示されています。
補足:試算について
記事内の時間削減効果は実測値に基づく試算です。実際の環境により結果は異なる可能性があります。詳細な前提条件と計算根拠はリポジトリのREADME.mdを参照してください。
ただし、削減率99.9999%とカバレッジ96%は事実です。