ChatGPTにDI(依存性注入)について聞いてみました(続き)。
タイトル、文章、イラスト: ChatGPT
登場人物
- ミナト(左): 新人エンジニア。C#は書けるようになってきたけど、テストはまだ苦手。
- ハルカ(右): 頼れる先輩。説明が丁寧で、コーヒー片手に教えてくれる系。
1. テストってやっぱりむずかしい
ミナト「はぁ~……テスト、また失敗しました……」
ハルカ「お、珍しく落ち込んでるじゃん。どしたの?」
ミナト「ユニットテストを書いてたんですけど、依存してるクラスのせいでうまくいかなくて……」
ハルカ「ふむふむ。ちなみにどんな感じのコード?」
C#:
public class MyApp
{
private Logger _logger = new Logger();
public void Run() => _logger.Write("Hello");
}
ミナト「このLoggerが原因で……テストで何が出力されるか確認できないんですよ」
ハルカ「あー、それね。newしちゃってる問題だね」
2. テストしにくいコードの問題点
ハルカ「MyAppが自分でLoggerを作っちゃってるでしょ?これが密結合ってやつ。変更しづらくて、テストもしにくい」
ミナト「じゃあ、どうすればいいんですか……?」
ハルカ「そこでDIの出番ってわけよ!」
ミナト「あっ! あのILoggerとかで渡すやつですね!」
3. DIを使った「テストしやすい」形に書き換え
C#:
public interface ILogger
{
void Write(string message);
}
public class ConsoleLogger : ILogger
{
public void Write(string message) => Console.WriteLine(message);
}
public class MyApp
{
private readonly ILogger _logger;
public MyApp(ILogger logger)
{
_logger = logger;
}
public void Run() => _logger.Write("Hello");
}
ミナト「なるほど~! ILoggerをコンストラクタで受け取るようにすれば……」
ハルカ「そう! どんなILoggerを使うかは外の世界が決める。だからテストではモックを渡せばいいんだよ」
ミナト「モック……やってみます!」
4. モックでユニットテスト!
C#:
public class MockLogger : ILogger
{
public string? LastMessage { get; private set; }
public void Write(string message)
{
LastMessage = message;
}
}
[TestMethod]
public void Run_LogsHello()
{
var logger = new MockLogger();
var app = new MyApp(logger);
app.Run();
Assert.AreEqual("Hello", logger.LastMessage);
}
ミナト「あ! これ……ちゃんと中のWrite()が呼ばれたか確認できてる!」
ハルカ「そうそう。これがDI×テストの醍醐味。振る舞いを記録できるから、見えない部分も検証できる」
ミナト「何をしたかが見えるって、安心感ありますね」
5. ちょっと休憩: DIとテストの関係を図にすると……
ハルカ「本番用もテスト用も、同じインターフェースに従うってのがポイント」
ミナト「インターフェース……大事ですね(復唱)」
6. テストしやすいコードは良いコード!
ハルカ「DIを使ってると、テストしやすい設計が自然にできるようになる」
ミナト「確かに!やってることはシンプルなのに、すごく柔軟になる気がします」
ハルカ「あと、テストのときだけDI登録を変えるって技もあるよ。HostのConfigureServicesでテスト用サービスを渡したりね」
ミナト「え、それもできるんですか!? DI、奥が深いですね……」
ハルカ「でしょ?でも、入り口は今やったモックパターンだけで十分強い武器になるよ」
まとめ: テストが楽になると、コードも育てやすくなる!
| DIで得られるテストのメリット | 内容 |
|---|---|
| 差し替え可能 | テスト用実装に切り替えられる |
| 動作の中身が見える | モックで呼び出し確認できる/td> |
| よりシンプルなテストが書ける | DIのおかげで依存解決が楽/td> |
| 自然と責務が分かれていく | 設計も整いやすくなる/td> |


0 件のコメント:
コメントを投稿