はじめに
自作のC# RoslynアナライザーのCSharpIngeniousAnalyzerで、各ルールの動作を手動確認するための使い捨てPlaygroundプロジェクトを使っていました。
しかし解析項目が多くなり、手動テストに限界を感じていました。
そこで、xUnitでのテスト環境を構築するために、テストコード生成をLLMに依頼しました。
その際、最初にざっくり依頼した場合と、適切なコンテキスト(観点を具体的に指定)を渡した場合とで、LLMの返答の質がここまで変わるとは思っていませんでした。
前提条件
- リポジトリ:
CSharpIngeniousAnalyzer(この時点で13ルール) - テスト構成: xUnit + Microsoft.CodeAnalysis.Testing
- 使用ツール: Claude Code
やってみたこと
1. 不適切にも程があるコンテキスト
「自動テストコードを作成して、テストを実行して」
その結果、生成されたテスト項目は105件でした。
% dotnet test
復元が完了しました (0.2 秒)
CSharp_IngeniousAnalyzer netstandard2.0 成功しました (0.9 秒) → /Users/.../CSharp_IngeniousAnalyzer/bin/Debug/netstandard2.0/CSharp_IngeniousAnalyzer.dll
CSharp_IngeniousAnalyzer.Tests net10.0 成功しました (0.9 秒) → bin/Debug/net10.0/CSharp_IngeniousAnalyzer.Tests.dll
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.4.5+1caef2f33e (64-bit .NET 10.0.7)
[xUnit.net 00:00:00.32] Discovering: CSharp_IngeniousAnalyzer.Tests
[xUnit.net 00:00:00.33] Discovered: CSharp_IngeniousAnalyzer.Tests
[xUnit.net 00:00:00.33] Starting: CSharp_IngeniousAnalyzer.Tests
[xUnit.net 00:00:05.52] Finished: CSharp_IngeniousAnalyzer.Tests
CSharp_IngeniousAnalyzer.Tests テスト net10.0 成功しました (6.3 秒)
テスト概要: 合計: 105, 失敗数: 0, 成功数: 105, スキップ済み数: 0, 期間: 6.3 秒
8.6 秒後に 成功しました をビルド
2. 真面目に考えた適切なコンテキスト
「各アナライザーのソースコードを読んで分岐(early return、条件分岐、異常系)を洗い出し、正常系・異常系・しきい値・カバレッジを意識したテストコードを作成し、実行して」と依頼しました。
生成されたテスト項目数は219件でした。
% dotnet test
復元が完了しました (0.2 秒)
CSharp_IngeniousAnalyzer netstandard2.0 成功しました (0.1 秒) → /Users/.../CSharp_IngeniousAnalyzer/bin/Debug/netstandard2.0/CSharp_IngeniousAnalyzer.dll
CSharp_IngeniousAnalyzer.Tests net10.0 成功しました (0.1 秒) → bin/Debug/net10.0/CSharp_IngeniousAnalyzer.Tests.dll
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.4.5+1caef2f33e (64-bit .NET 10.0.7)
[xUnit.net 00:00:00.31] Discovering: CSharp_IngeniousAnalyzer.Tests
[xUnit.net 00:00:00.32] Discovered: CSharp_IngeniousAnalyzer.Tests
[xUnit.net 00:00:00.33] Starting: CSharp_IngeniousAnalyzer.Tests
[xUnit.net 00:00:05.53] Finished: CSharp_IngeniousAnalyzer.Tests
CSharp_IngeniousAnalyzer.Tests テスト net10.0 成功しました (6.1 秒)
テスト概要: 合計: 219, 失敗数: 0, 成功数: 219, スキップ済み数: 0, 期間: 6.1 秒
6.7 秒後に 成功しました をビルド
3. 結果
| Before | After | |
|---|---|---|
| テストケース数 | 105件 | 219件 |
+114件、ほぼ2倍 になりました。
さらに、このカバレッジ拡充の過程で実装側のバグも3件見つかり、あわせて修正しています。
-
null == nullをis nullに書き換えてコンパイルエラーを起こす不具合(NULL001) - コンストラクタ内の
.ToList()検出漏れ(LINQ002) - 比較先の文字列プレフィックスが食い違っていて、実質デッドコードになっていた分岐(共通ロジック)
わかったこと
- 「テストコードを書いて」だけだと、LLMは典型的な正常系を1〜2個書いて満足しがち
- 「正常系・異常系・しきい値・カバレッジを意識」という言葉を添えるだけで、それが暗黙のチェックリストとして働き、境界値ちょうどのケースやearly-return分岐まで拾うようになった
- 「実装されているが、意図した分岐の両方向が検証されているか」は、この種のレビュー観点を明示しないと出てこなかった
後頭部に刺さったヒトコト
- コンテキストがない : 一般的な正解 で埋めようとする
- コンテキストがある : その状況固有の最適解 で埋める
おわりに
コンテキストが大切だということは分かっていながら、面倒なので短く依頼してしまいがちです。
しかし、テストコードの生成依頼一つで、ここまで結果が変わるのは正直驚きでした。
「テスト書いて」だけで終わらせず、観点を一言添えるだけでコストなくカバレッジが上がるので、今後は横着をせずに習慣化したいと思います。
同じような経験をされた方がいれば、ぜひ教えてください。
- NuGet: CSharp_IngeniousAnalyzer
- GitHub: IngeniousDesign/CSharp_IngeniousAnalyzer
最後までお読みいただき、ありがとうございました!