xUnit + Moq で完全自動化!効率的なユニットテスト生成スキル

📌 概要

MAUI プロジェクトのテストコードは「定型的で手書きが苦痛」ですよね。このスキルは xUnit + Moq を使用した ViewModel・Service・Repository のユニットテストを 自動生成 することで、テスト駆動開発(TDD)を実践しやすくします。

🤔 背景・なぜ必要か

従来のテスト作成の課題

// ❌ テストコードの定型部分が多い
public async Task GetHabits_WhenHabitsExist_ReturnsHabitList()
{
    var habits = new List<Habit> { ... };
    _mockRepository.Setup(r => r.GetAllAsync()).ReturnsAsync(habits);
    var viewModel = new HabitListViewModel(_mockRepository.Object);
    
    await viewModel.LoadHabitsAsync();
    
    Assert.NotNull(viewModel.Habits);
    _mockRepository.Verify(r => r.GetAllAsync(), Times.Once);
}

毎回、Arrange(準備)→ Act(実行)→ Assert(検証) の流れを書く必要があり、ビジネスロジックの仕様を考えるより「テストコードの書き方」に頭を使ってしまいます。

スキルの解決方法

  • 自動生成: Copilot が「ViewModel のメソッド名」から必要なテストを判定
  • 命名規則統一: [メソッド]_[シナリオ]_[期待結果] で可読性維持
  • テスト階層化: ViewModel → Service → Repository の順で優先度付け

💻 実装方法

ステップ1: テストプロジェクトフォルダ構成

HabitTracker.Tests/
├── Fixtures/
│   └── MockRepositoryFixture.cs
├── ViewModels/
│   └── HabitListViewModelTests.cs
├── Services/
│   └── HabitServiceTests.cs
└── Repositories/
    └── HabitRepositoryTests.cs

ステップ2: ViewModel テスト自動生成

ViewModel HabitListViewModel に対して、以下をスキルに指示:

「HabitListViewModel の LoadHabitsAsync メソッドのユニットテストを xUnit + Moq で生成してください」

生成されたテスト例:

[Fact]
public async Task LoadHabitsAsync_WhenHabitsExist_PopulatesHabitList()
{
    // Arrange
    var habits = new List<Habit>
    {
        new Habit { Id = 1, Name = "Running", IsActive = true }
    };
    _mockRepository.Setup(r => r.GetAllAsync())
        .ReturnsAsync(habits);
    
    var viewModel = new HabitListViewModel(_mockRepository.Object);
    
    // Act
    await viewModel.LoadHabitsAsync();
    
    // Assert
    Assert.NotNull(viewModel.Habits);
    Assert.Single(viewModel.Habits);
    _mockRepository.Verify(r => r.GetAllAsync(), Times.Once);
}

[Fact]
public async Task AddHabitAsync_WhenNameEmpty_DoesNotAdd()
{
    var viewModel = new HabitListViewModel(_mockRepository.Object);
    viewModel.HabitName = string.Empty;
    
    await viewModel.AddHabitAsync();
    
    _mockRepository.Verify(r => r.AddAsync(It.IsAny<Habit>()), Times.Never);
}

ステップ3: テスト実行とカバレッジ測定

# テスト実行
dotnet test HabitTracker.Tests

# カバレッジ計測
dotnet test HabitTracker.Tests /p:CollectCoverage=true

⭐ ポイント

1. モック設定の統一性

  • すべての Repository モックは IHabitRepository を共通化
  • Setup パターンは「GetAllAsync → ReturnsAsync」で統一

2. テスト優先度

ViewModel(最優先)  ← 80% 以上のカバレッジ目標
    ↓
Service(中優先)   ← 複雑なビジネスロジックがある場合
    ↓
Repository(参考)  ← EF Core の動作はマイクロソフトが保証

3. よくあるミス

  • Times.Once を忘れて Verify しない
  • ❌ Async メソッドで .Wait() を使う(デッドロック)
  • ❌ Mock の戻り値を null にする(NullReferenceException)

4. テスト命名規則の重要性

// ✅ 良い例
[Fact]
public async Task LoadHabitsAsync_WhenHabitsExist_PopulatesHabitList()

// ❌ 悪い例
[Fact]
public async Task TestLoadHabits()

✅ まとめ

ユニットテスト生成スキルは、TDD を実践するための「最初のハードル」を下げる ものです。テストコード自体ではなく「どのテストケースが必要か」に集中できます。

カバレッジ 80% 以上を目指して、安心して機能追加できるプロジェクト文化を作りましょう!


📚 参考資料

コメント

タイトルとURLをコピーしました