14
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

xUnit で始める C# 単体テスト入門

14
Posted at

C# で開発をしていると、単体テストを書く機会は必ず訪れます。
ただ、いざ書こうとすると「どこから手をつければいいんだろう」と迷うことも多いですよね。

この記事では、xUnit を使った単体テストの基本を中心に、
実務でつまずきやすいポイントや、外部依存を扱う際の考え方も交えて紹介します。


xUnit を選ぶ理由

C# のテストフレームワークには MSTest、NUnit、xUnit などがありますが、
xUnit は次のような理由で扱いやすいと感じています。

  • コードがシンプルで読みやすい
  • [Fact] と [Theory] の使い分けが直感的
  • 依存注入(DI)と相性が良い
  • .NET の公式テンプレートでも採用されている

まずは基本のテストから見ていきましょう。


最小の単体テストを書いてみる

xUnit の基本をつかむには、まずはシンプルなテストを書くのが一番です。

テスト対象のクラス:

public class Calculator
{
    public int Add(int a, int b) => a + b;
}

xUnit のテスト:

using Xunit;

public class CalculatorTests
{
    // 足し算が正しく行われることを確認
    [Fact]
    public void Add_ShouldReturnCorrectSum()
    {
        // Arrange
        var calc = new Calculator();

        // Act
        var result = calc.Add(2, 3);

        // Assert
        Assert.Equal(5, result);
    }
}

テストを読みやすくする AAA パターンの考え方

単体テストは、書く人だけでなく「読む人」にとっても分かりやすいことが重要です。
そのための基本形として広く使われているのが AAA(Arrange / Act / Assert)パターンです。

● Arrange(準備)

テストに必要なオブジェクトやデータを準備するフェーズです。

  • テスト対象のインスタンスを作る
  • 入力値を用意する
  • 必要ならモックをセットアップする

Arrange が複雑になりすぎる場合、
「クラスの責務が大きすぎるサイン」であることもあります。

● Act(実行)

テスト対象のメソッドを 1 回だけ 呼び出します。

  • 余計な処理を入れない
  • 1 テストにつき 1 メソッド呼び出しが基本

Act が複数あると、テストの意図が曖昧になりがちです。

● Assert(検証)

Act の結果が期待通りかどうかを確認します。

  • 戻り値の検証
  • 状態の変化の確認
  • 例外の発生確認

よく使う Assert の例

Assert.Equal(expected, actual);              // 値の一致
Assert.NotNull(obj);                         // null でないこと
Assert.True(condition);                      // 条件が true
Assert.Throws<Exception>(() => method());    // 例外の発生

実務では Assert が増えすぎるとテストが壊れやすくなるため、
「1 テスト 1 アサーション」を基本にすると安定します。


[Theory] を使ったパラメータ化テスト

複数パターンをまとめてテストしたいときに便利なのが [Theory] です。

public class CalculatorTests
{
    // 複数パターンで正しく計算されることを確認
    [Theory]
    [InlineData(1, 2, 3)]
    [InlineData(10, 20, 30)]
    [InlineData(-5, 5, 0)]
    public void Add_ShouldReturnCorrectSum_ForMultiplePatterns(int a, int b, int expected)
    {
        var calc = new Calculator();

        var result = calc.Add(a, b);

        Assert.Equal(expected, result);
    }
}

境界値や複数パターンの検証が必要な場面で特に役立ちます。


外部依存があるコードをテストしたいときの考え方

単体テストを書いていると、次のようなケースに出会います。

  • DB にアクセスする処理がある
  • 外部 API を呼び出す
  • ファイル I/O が含まれている
  • 依存オブジェクトの動きを自由に変えてテストしたい

こうした外部依存があるコードは、そのままテストすると遅くなったり、
環境によって結果が変わったりして、テストが安定しません。

そこで役に立つのが モック(mock) という考え方です。


モックの基本概念

モック(mock)は 「外部依存の代わりに使う偽物オブジェクト」 です。

  • DB や API を本当に呼ばずにテストできる
  • 戻り値を自由に決められる
  • 例外パターンも再現できる

つまり、テストしたいロジックだけに集中するための道具です。

C# では Moq というモックライブラリがよく使われます。
ここでは、実務で最低限知っておくと便利な Moq の使い方を紹介します。


Moq を使った最小のモック例

テスト対象のサービス:

public interface IUserRepository
{
    User? GetUser(int id);
}

public class UserService
{
    private readonly IUserRepository _repo;

    public UserService(IUserRepository repo)
    {
        _repo = repo;
    }

    public string GetUserName(int id)
    {
        var user = _repo.GetUser(id);
        return user?.Name ?? "Unknown";
    }
}

Moq を使ったテスト:

using Moq;
using Xunit;

public class UserServiceTests
{
    // ユーザーが存在する場合は名前を返すことを確認
    [Fact]
    public void GetUserName_ShouldReturnUserName_WhenUserExists()
    {
        // Arrange
        var mockRepo = new Mock<IUserRepository>();
        mockRepo.Setup(x => x.GetUser(1))
                .Returns(new User { Id = 1, Name = "Taro" });

        var service = new UserService(mockRepo.Object);

        // Act
        var result = service.GetUserName(1);

        // Assert
        Assert.Equal("Taro", result);
    }
}

Moq の動きを理解する

new Mock<IUserRepository>()

IUserRepository の「偽物」を作っています。
この時点では中身は空っぽで、何を呼んでも既定値(参照型なら null)を返します。

Setup(x => x.GetUser(1))

GetUser(1) が呼ばれたらどう振る舞うか」を定義する準備です。

.Returns(new User { ... })

実際に返す値を指定します。

mockRepo.Object

モックの “本体” です。
UserService に渡すことで、
本物のリポジトリの代わりにモックが使われる ようになります。


実務でテストを書くときのコツ

  • テスト名は仕様を書く
  • AAA パターンを徹底する
  • Theory で複数パターンを網羅する
  • 外部依存はモックで切り離す
  • バグを見つけたら再発防止テストを 1 本追加する

テストは「未来の自分を助けるための投資」です。
xUnit の基本を押さえておくだけで、開発が本当に楽になります。


14
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?