第7章:重複を“検知して戻す”仕組み(テスト+AI+IDE)🧪🤖🛠️
7.1 この章のゴール 🎯✨
DRYって、がんばっても…気づくと戻るんですよね🥲 だからこの章では 「気合」じゃなく「仕組み」 にします💪🌸
ゴールはこの3つ👇
- 重複を消しても壊れない(=テストが守ってくれる)🧪✅
- 重複が増えたら早めに気づく(=IDEで検知)🛠️👀
- AIで棚卸し&テスト生成を加速(でも鵜呑みはしない)🤖🧠
7.2 DRYを“仕組み化”する「3点セット」🔁✨
(A) テスト 🧪:変更しても安心の“保険”
DRYはリファクタが多いので、テストがあると一気に怖さが減ります😌 (テストがない状態でDRYすると、だいたい途中でビビって止まるあるある💦)
(B) IDE 🛠️:重複を“見える化”
- リファクタ機能(メソッド抽出/リネームなど)
- 検索・参照・分析(似たコードに早めに気づく)
- コード品質チェック(アナライザー等)
(C) AI 🤖:棚卸し&テスト生成の“加速装置”
- 「同じ意味の処理、複数ない?」を洗い出し🧺
- 「この振る舞いのテスト作って」を高速化🚀
- ただし 最終判断は自分(ここ大事)🧠✨
7.3 “最小のテスト”だけでいいよ作戦 🧪🌱

最初から完璧テストはしんどいので、ミニでOKです😊
✅ まずはこの3種類だけ!
- 代表値テスト:よくある入力で期待どおり?🙂
- 境界値テスト:しきい値(例:送料無料ライン)ちょうどは?🎯
- 例外/弾くテスト:ダメ入力はちゃんと止まる?🚧
DRYの目的は「まとめること」じゃなくて「ルールを1つにすること」なので、 テストも“ルールが守られてるか”だけ押さえれば強いです💪✨
7.4 回すのがラクになると勝ち:Test Explorer & dotnet test 🚀🧪

7.4.1 Test Explorer(IDEでポチポチ)🖱️✨
Test Explorer では、テストの一覧・フィルタ・プレイリスト作成・デバッグ実行などができます🧪🔎 さらに(エディションによっては)コードカバレッジ分析もできます📈 (Microsoft Learn)
超おすすめショートカット感覚
- 「直す」→「すぐ実行」→「安心して次へ」🔁🌸 これを回せるとDRYが一気に上達します💨
7.4.2 dotnet test(CLIでサクッと)⌨️✨
dotnet test は、ソリューションをビルドしてテストを実行します🧪
テスト実行は VSTest または Microsoft Testing Platform (MTP) を使います (Microsoft Learn)
- VSTest:MSTest / NUnit / xUnit などに対応して動かせる(定番) (Microsoft Learn)
- MTP:より軽量で高速寄り、フィルタ等の体験も変わる(選べる) (Microsoft Learn)
よく使う例👇(まずはこれだけでOK!)
## ぜんぶ実行
dotnet test
## 失敗したテストだけ追いかけたい時の定番:フィルタ(例)
dotnet test --filter "FullyQualifiedName~Shipping"
(フィルタの考え方はランナーで差があるので、困ったら「まずTest Explorerで」でも全然OK😊)
7.5 AIの使いどころ:①テスト生成 ②重複棚卸し 🤖🧪🧺
7.5.1 Copilotで“テスト生成”を時短する 🧪⚡
Visual Studio の Copilot Chat には、テスト生成に特化した使い方があります。
例:チャットで @test #target を使うと、ソリューション/プロジェクト/クラス/メンバー単位でテスト生成を始められます🧪🤖 (Microsoft Learn)
イメージ👇
@test #OrderCalculator
注意ポイント(ここが差が出る🥺)
- 生成されたテストが「仕様」じゃなく「実装のコピー」になってない?👀
- 期待値が雑にベタ書きされてない?(根拠ある?)🧠
- 境界値が入ってる?(送料無料ライン等)🎯
7.5.2 Copilot Chatに“前提(文脈)”を覚えさせる 📌🤖
毎回同じ説明を書くの、ダルいですよね😇 Copilot Chat は、コンテキストをファイル等に置いて“自動で含める”考え方が用意されています(カスタム命令/プロンプトファイルの方向)📝 (Microsoft Learn)
→ これをやると「このプロジェクトのルール」に沿った提案が増えやすいです✨
7.5.3 “重複棚卸し”のAIプロンプト例 🧺🤖
そのままコピペで使えるやつ👇
このソリューションで「同じ知識(ビジネスルール)」が複数箇所に散ってそうな所を、
(1) 割引ルール (2) 送料ルール (3) 入力バリデーション (4) ステータス文字列
に分類して候補リスト化して。根拠として該当ファイル/メソッド名も添えて。
7.6 IDEで“重複を検知”して戻す 🛠️👀🔁
7.6.1 Quick Actions(リファクタの入口)✨
Visual Studio の Quick Actions は、リファクタ・生成・修正をワンアクションで出してくれます🪄 (抽出、名前変更、不要using整理…など) (Microsoft Learn)
DRY初心者は特に、
- 「手で直す」より「IDEに安全にやらせる」 がミスりにくいです😊🛡️
7.6.2 コード分析(“怪しい匂い”を早めに)🕵️♀️✨
Visual Studio にはコード品質を評価する分析機能がまとまっていて、警告やルールで気づけます🔎 (Microsoft Learn) “重複そのもの”じゃなくても、**重複が生まれやすい原因(複雑すぎ等)**を早めに潰せます💣➡️🌿
7.6.3 コードクローン分析(※使えるなら強い)🧬👀
Visual Studio の「Architecture analysis & modeling tools」系の機能として、**Code clone(コードの重複検出)**は Enterprise で提供される扱いです (Microsoft Learn) また、テスト/品質改善系のまとめの中でも code clone analysis が触れられています (Microsoft Learn)
もしこの機能が使える環境なら、 「似てるコードが増えてきた…」を早めに検知できて便利です😳✨ (ただし“似てる”=“同じルール”ではないので、最後は人間が判断🧠)
7.7 演習:「重複削除→テスト追加→安心してリファクタ」3点セット🌟🧪🔁
ここでは分かりやすく 送料+割引の例でいきます💰📦
ステップ0:まず“仕様メモ”を書く📝✨
- 会員:10%引き(切り捨て)
- 送料:割引後の金額が5000以上なら無料、未満なら500円
→ これが「知識(ルール)」です。ここが複数箇所に散るとDRY違反😵
ステップ1:ミニテストを3本だけ作る🧪🌱
MSTest例(最小)👇
using Microsoft.VisualStudio.TestTools.UnitTesting;
[TestClass]
public class CheckoutTests
{
[TestMethod]
public void Member_6000yen_DiscountedAndFreeShipping()
{
// 6000 * 0.9 = 5400, shipping 0 => 5400
var total = Checkout.CalcTotalForMember(6000);
Assert.AreEqual(5400, total);
}
[TestMethod]
public void Member_5000yen_DiscountedAndShippingCharged()
{
// 5000 * 0.9 = 4500, shipping 500 => 5000
var total = Checkout.CalcTotalForMember(5000);
Assert.AreEqual(5000, total);
}
[TestMethod]
public void Guest_5000yen_FreeShipping()
{
// guest no discount => 5000, shipping 0 => 5000
var total = Checkout.CalcTotalForGuest(5000);
Assert.AreEqual(5000, total);
}
}
ポイントはこれ👇
- “全部”テストしない🙅♀️(今はミニでOK)
- **境界値(5000)**を入れる🎯
- 期待値は「ルールから計算できる数字」にする🧠✨
ステップ2:DRY(重複の核=ルール)を1箇所に寄せる✂️🧩
次は実装側。例として「割引後金額→送料→合計」を共通化します👇
public static class Checkout
{
public static int CalcTotalForMember(int subtotal)
=> CalcTotal(subtotal, discountRate: 0.9);
public static int CalcTotalForGuest(int subtotal)
=> CalcTotal(subtotal, discountRate: 1.0);
private static int CalcTotal(int subtotal, double discountRate)
{
int discounted = (int)(subtotal * discountRate);
int shipping = CalcShipping(discounted);
return discounted + shipping;
}
private static int CalcShipping(int discountedSubtotal)
=> discountedSubtotal >= 5000 ? 0 : 500;
}
ここで起きてること👇
- 同じ送料ルールが
CalcShippingに集約📦 - 会員/非会員の違いは「割引率」だけに💡
- テストが通る限り、振る舞いは壊れてない✅🧪
ステップ3:すぐテスト実行(安心して次へ)🔁🧪
- Test Explorerで Run All でもOK 🖱️ (Microsoft Learn)
- あるいは
dotnet testでサクッと⌨️ (Microsoft Learn)
テストが通ったら勝ちです🎉 この「小さく直して、すぐ確認」を回せる人がDRY強い💪🌸
ステップ4:AIで“追加の重複”を棚卸し🧺🤖
ここで Copilot Chat に
- 「送料/割引と同じ意味の処理が他にもない?」
- 「このルールに対する足りないテストは?」
って聞くと、抜けが見つかりやすいです🔎✨
テスト生成も
@test #Checkoutみたいに投げられます🧪🤖 (Microsoft Learn)
7.8 よくある事故と回避テク⚠️🛟
-
テストが“実装のコピー”になってる → 期待値はルールから計算する(テスト内で理由を書いちゃうのもOK)📝
-
共通化したけど、引数が増えすぎて読めない → “違い”が2個を超えたら、次章(落とし穴)案件の匂い🐙⚠️
-
AIの提案を丸呑みして、読みづらくなる → 採用基準は「3秒で意図が読める?」⏱️👀
7.9 まとめ:明日から回すチェックリスト✅💖
- ルール(知識)を1行で言える?🧠
- 代表値+境界値+弾く、のミニテスト3本ある?🧪
- リファクタは“小さく”→すぐ実行、できてる?🔁
- IDEのQuick Actionsで安全に直してる?🛠️ (Microsoft Learn)
- AIには「棚卸し」と「テスト生成」を頼んで、最後は自分で判断してる?🤖✅ (Microsoft Learn)
必要なら、この第7章の「演習」をもう1本増やして、例外処理(try/catchの重複)+ログのDRYも同じ流れ(ミニテスト→小さくリファクタ→AI棚卸し)で作れます🚨🧪🤖