【Visual Studio (2022)】 C# アプリのユニットテストに「xUnit」を導入する

ユニットテスト(単体テスト)は、アプリケーションの品質を高めるうえで非常に重要なテストです。本ブログでは、Visual Studio 2022C# アプリにユニットテスト「xUnit」を導入する手順を具体的に紹介します。

ユニットテストとは

  • 目的     :個々の関数やクラスなど「最小単位」が正しく動作するかを検証
  • 実行タイミング:コードを書くたびに都度実行
  • テスト対象  :ビジネスロジック、計算処理、バリデーションなど
  • 自動化    :コードの変更が他の部分に影響を与えていないか、すぐにチェックが可能

※バリデーション
 入力されたデータや値が「正しい形式・範囲・ルール」に従っているかどうかをチェック

テストツールを使用する主な理由

テストツールを使用する主な理由

  • 手動テストの手間を削減できる
  • コードの品質を自動的に検証できる
  • 同一条件のテストが簡単に何回でもできる

主なユニットテストツール

  • MSTest (Microsoft製・標準テスト)
    • Visual Studio に標準搭載
    • シンプルな構成で導入しやすい
    • モダンな機能やDI対応はやや弱い
  • xUnit(モダン & .NET公式推奨)
    • Microsoft推奨(.NET Core/ASP.NET Coreテンプレートでも採用)
    • テストクラスはインスタンス単位で作成される(副作用を避ける設計)
    • 軽量・高速でCI/CDにも向いている
    • ドキュメント・拡張性も優秀
  • NUnit(老舗・高機能で柔軟)
    • C# テストの中では古いフレームワーク
    • パラメータ化やセットアップ/ティアダウンが多機能
    • GUI(NUnit GUI)でもテストが実行可能
    • .NET Framework時代からの資産と親和性が高い

どのテストツールを使用すべきか

  1. 新規開発 or .NET Core / .NET 6+ → xUnit が最有力
  2. 既存資産が MSTest → MSTest 継続でも可
  3. 高機能なテストやGUI実行が必要 → NUnit

本ブログでは、.NET環境で広く使われているオープンソースのxUnitを使用した手順を紹介します。

xUnitを使用したユニットテストの準備

テスト対象となるプロジェクトとクラスの作成

プロジェクト名を「SampleApp」とし、その中にテスト対象となるクラス「Calculator.cs」を作成します。

  • アプリの種類
    • C#コンソールアプリ
  • .Netのバージョン
    • 8.0
// SampleApp.Program.cs
// See https://aka.ma/new-console-template for more information

using SampleApp;

Calculator Calculator_Method = new();
int Add_result = Calculator_Method.Add(5, 3);
Console.WriteLine("Add_result: " + Add_result);
// SampleApp.Calculator.cs

namespace SampleApp
{
    //テスト対象の簡単な関数
    public class Calculator
    {
        public int Add(int a, int b) => a + b;
    }
}

テストに必要なパッケージのインストール

  • NuGetで以下をインストール
    • xunit             Ver. 2.9.3
    • xunit.runner.visualstudio   Ver. 3.1.0
    • Microsoft.NET.Test.Sdk      Ver. 17.13.0
  • ソリューション’SampleApp’を右クリックし、「ソリューションのNuGetパッケージの管理」を選択
  • 参照タグの検索欄にインストールするパッケージ名を入力して検索し、表示されたパッケージをクリック
  • インストールするプロジェクトにチェックを入れインストール
  • 確認画面が表示されるので「適用」をクリックするとインストールが開始
  • 「インストール済」タグでインストールの可否を確認

xUnitテストプロジェクトの作成

同一ソリューション内にxUnitテストプロジェクト「SampleApp.Tests」プロジェクトを作成

  • ソリューションを右クリックして「追加」→「新しいプロジェクト」
  • 「検索」欄に「xUnit」を入力し「xUnitテストプロジェクト」を選択
  • プロジェクト名を入力し「次へ」をクリックしてxUnitテストプロジェクトを作成
  • プロジェクト「SanpleApp」への参照を設定
    • プロジェクトを右クリックし「追加」→「プロジェクト参照」

  ・プロジェクト「SampleApp」にチェックを入れる

xUnitによるユニットテスト例

「SampleApp.Tests」プロジェクト内に下記のコードを作成します。

  • IClassFixture<T>を使用したテストで使用する、CalculatorFixtureクラス
// SampleApp.Tests/CalculatorFixture.cs
using SampleApp;

public class CalculatorFixture
{
    public Calculator Calculator { get; private set; }

    public CalculatorFixture()
    {
        // テストクラス全体で 1 回だけ呼ばれる
        Calculator = new Calculator();
        Console.WriteLine("Fixture: Calculator initialized");
    }
}
  • テストを実施するCalculatorTestsクラス
// SampleApp.Tests/CalculatorTests.cs

using Xunit;
using SampleApp;

namespace SampleApp.Tests
{
    public class CalculatorTests : IClassFixture<CalculatorFixture>
    {
        //--------------------------------------------------------------------
        // [Fact]を使用したテスト
        //--------------------------------------------------------------------

        [Fact]
        public void Add_2plus3_Returns5()
        {
            var calc = new Calculator();
            var result = calc.Add(2, 3);
            Assert.Equal(5, result);
        }

        //--------------------------------------------------------------------
        // [Theory][InlineData]を使用したテスト
        //--------------------------------------------------------------------

        [Theory]
        [InlineData(5, 5, 10)]
        [InlineData(50, 50, 100)]
        [InlineData(0, 0, 0)]
        public void Subtract_VariousInputs_ReturnsExpected(int a, int b, int expected)
        {
            var calc = new Calculator();
            var result = calc.Add(a, b);
            Assert.Equal(expected, result);
        }


        //--------------------------------------------------------------------
        // [Theory][MemberData]を使用したテスト
        //--------------------------------------------------------------------

        public static IEnumerable<object[]> AddData =>
        new List<object[]>
        {
            new object[] { 1, 2, 3 },
            new object[] { -1, -1, -2 },
            new object[] { 0, 0, 0 }
        };

        [Theory]        [MemberData(nameof(AddData))]
        public void Add_WithMemberData_ReturnsExpected(int x, int y, int expected)
        {
            var calc = new Calculator();
            Assert.Equal(expected, calc.Add(x, y));
        }

        //--------------------------------------------------------------------
        //  IClassFixture<T> を使用したテスト
        //--------------------------------------------------------------------

        private readonly CalculatorFixture _fixture;

        public CalculatorTests(CalculatorFixture fixture)
        {
            _fixture = fixture; // 共有フィクスチャを注入
        }

        [Fact]
        public void Add_4plus5_Returns5()
        {
            int result = _fixture.Calculator.Add(4, 5);
            Assert.Equal(9, result);
        }
    }
}

テストの実行

メニューの「テスト」→「全てのテストを実行」をクリックすると、xUnitは全てのテストコードを実行し、結果を下図の様に表示します。グリーン表示はテストが合格である事を示しています。

不合格の場合は下図のように赤く表示されます。

テストコードの解説

[Fact]コード

引数なしのテストコードを示します。

  • [Fact]コードの後にテスト対象となる関数を呼び出し
  • 結果を「result」で受け取って
  • Assert.Equal(5, result)で、正しい結果と関数から帰ってきた数値を比較

Assert.Equal(5, result)がTrueならばテストは合格。

[Theory] [InlineData] の組み合わせ

複数の組み合わせのテストを一度に実行します。

  • [Theory]の後に結果と引数を[InlineData(10, 5, 5)]コードに記述
  • (Subtract_VariousInputs_ReturnsExpected)内でテスト対象となる関数「calc.Add(a, b)」を呼び出して
  • Assert.Equal(expected, result)で、正しい結果と関数から帰ってきた数値を比較

Assert.Equal(expected, result)がTrueならばテストは合格。

[Theory][MemberData]の組み合わせ

外部ファイルやデータベースに近い形式にも対応できます。

  • 引数と正解値の配列のListを作成し
  • [Theory]の後に[MemberData(nameof(AddData))]でテストデータのListを指定
  • Add_WithMemberData_ReturnsExpected内で「calc.Add(a, b)」を呼び出して
  • 正しい結果と関数から帰ってきた数値を比較

Assert.Equal(expected, calc.Add(x, y))がTrueならばテストは合格。

IClassFixture<T>を使用したテスト

複数のテストに共通する重たい初期化処理(例:DB接続、ファイル読み込みなど)に適しています。

  • CalculatorFixtureクラス
    Calculator インスタンスを一度だけ生成して保持
    ※一般的に、テストクラス全体で使用する共通オブジェクトの初期化処理を記述する
  • : IClassFixture<CalcuratorFixture>
    xUnitに「このテストクラスでCalculatorFixtureを使う」と宣言
  • CalculatorTests(CalculatorFixture fixture)
    xUnit がテストクラスを生成する際に、自動的に必要なフィクスチャ(共有オブジェクト)を生成して渡してくれる(DIのようなもの)
  • _fixture.Calculator.Add(…)
    フィクスチャの中の Calculator インスタンスを使ってメソッドをテスト

Assert.Equal(9, result)がTrueならばテストは合格。

よく使う Assert メソッド一覧

メソッド名検証内容
1Assert.Equal()値が等しいか
2Assert.NotEqual()値が異なるか
3Assert.True()条件が true か
4Assert.False()条件が false か
5Assert.Null()値が null か
6Assert.NotNull()値が null ではないか
7Assert.Throws<T>()例外がスローされたか

まとめ

xUnit は、C# で効率的にユニットテストを行うための強力なフレームワークです。

主なポイントは、

  • [Fact]:単純なテスト
  • [Theory][InlineData]:シンプルなデータ駆動テスト
  • [Theory][MemberData]:複雑なデータ管理や動的データの活用
  • IClassFixture<T>:重たい初期設定を1回だけ実行して各種テストに使用

xUnit を使いこなして、テストの品質と保守性を向上させましょう。

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