Chapter 10

10. テストとデバッグ

Hiromichi NOMATA
Hiromichi NOMATA
2025.02.28に更新

10.1 ユニットテストの基礎

ゆっくり霊夢:
「まずは、ユニットテストの基本について説明するわ。ユニットテストでは、各クラスやメソッドが単体で正しく動作しているかを検証するの。依存性注入とモックを活用することで、外部依存関係に左右されずテストできるのよ。」

ゆっくり魔理沙:
「その通りだぜ!たとえば、ProductServiceというクラスがあって、IProductRepositoryに依存しているとする。ここでは、Moqを使ってリポジトリのモックを作り、テストする例を見てみよう!」

// モデルの例
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
}

// リポジトリのインターフェイス
public interface IProductRepository
{
    Product GetProductById(int id);
}

// サービスクラス
public class ProductService
{
    private readonly IProductRepository _repository;
    public ProductService(IProductRepository repository)
    {
        _repository = repository;
    }
    
    public Product GetProduct(int id)
    {
        return _repository.GetProductById(id);
    }
}
// ユニットテストの例(xUnit + Moq)
using Xunit;
using Moq;

public class ProductServiceTests
{
    [Fact]
    public void GetProduct_ReturnsExpectedProduct()
    {
        // Arrange: モックの作成
        var mockRepo = new Mock<IProductRepository>();
        mockRepo.Setup(repo => repo.GetProductById(It.IsAny<int>()))
                .Returns(new Product { Id = 1, Name = "TestProduct" });
        
        var service = new ProductService(mockRepo.Object);
        
        // Act: テスト対象メソッドの実行
        var result = service.GetProduct(1);
        
        // Assert: 結果の検証
        Assert.NotNull(result);
        Assert.Equal("TestProduct", result.Name);
    }
}

ゆっくり霊夢:
「このように、Moqを使えば実際のデータベースや外部サービスに依存せずに、サービスクラスの動作だけを検証できるの。」


10.2 統合テストの実践

ゆっくり魔理沙:
「次は、統合テストについてだぜ。統合テストでは、複数のコンポーネントが連携して正しく動作するかを確認するんだ。ASP.NET Coreでは、TestServerやWebApplicationFactoryを使って実際のHTTPリクエストをシミュレートできるぜ!」

ゆっくり霊夢:
「たとえば、ホームページに対するリクエストが正しく処理されるかをテストする例を見てみましょう。」

using Microsoft.AspNetCore.Mvc.Testing;
using System.Net.Http;
using System.Threading.Tasks;
using Xunit;

public class HomeControllerIntegrationTests : IClassFixture<WebApplicationFactory<Startup>>
{
    private readonly HttpClient _client;
    
    public HomeControllerIntegrationTests(WebApplicationFactory<Startup> factory)
    {
        _client = factory.CreateClient();
    }
    
    [Fact]
    public async Task GetHomePage_ReturnsSuccessAndContainsWelcomeMessage()
    {
        // Act: ホームページへのGETリクエスト
        var response = await _client.GetAsync("/");
        response.EnsureSuccessStatusCode();
        var content = await response.Content.ReadAsStringAsync();
        
        // Assert: レスポンス内容に「Welcome」が含まれているか
        Assert.Contains("Welcome", content);
    }
}

ゆっくり魔理沙:
「このテストは、実際のHTTPリクエストを模倣して、コントローラとミドルウェアが正しく連携しているかを検証するんだぜ!」


10.3 効率的なデバッグ手法

ゆっくり霊夢:
「最後に、効率的なデバッグ手法について説明するわ。デバッグは、コード内の問題を迅速に発見し修正するための重要な工程よ。まずは、ローカル環境でのブレークポイント設定が基本ね。」

ゆっくり魔理沙:
「Visual StudioやVS Codeでは、ブレークポイントを設定して実行中の変数の値や処理の流れをリアルタイムで確認できるんだ。たとえば、以下のコードでブレークポイントを設定してみよう!」

using Microsoft.Extensions.Logging;

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;
    
    public HomeController(ILogger<HomeController> logger)
    {
        _logger = logger;
    }
    
    public IActionResult Index()
    {
        // ブレークポイントをここに設定して、処理の流れや変数の値を確認する
        _logger.LogInformation("Index action has been called.");
        return View();
    }
}

ゆっくり霊夢:
「また、デバッガツールでは、ウォッチウィンドウやローカル変数の表示、ステップ実行など、細かく調査できる機能が充実しているの。ログ出力を活用して、処理の状態を追跡するのも有効よ。」

ゆっくり魔理沙:
「こうして、ユニットテストと統合テストで問題を発見し、デバッガツールで原因を追究することで、効率的にバグを修正できるんだぜ!」


ゆっくり霊夢:
「これで、テストとデバッグの基本的な手法について理解できたかしら?ユニットテストで個々の機能を検証し、統合テストで全体の連携を確認し、そしてデバッグで細かい問題を解決するのよ。」

ゆっくり魔理沙:
「みんなも、ぜひ実際に手を動かしてテストコードを書き、ブレークポイントやログを活用しながら、効率的な開発を進めてくれよな!」