MSTest と .NET による単体テスト C#

このチュートリアルでは、単体テストの概念について学習するためにサンプル ソリューションを段階的に構築する対話型のエクスペリエンスを示します。 構築済みのソリューションを使用してチュートリアルに従う場合は、開始する前にサンプル コードを参照またはダウンロードしてください。 ダウンロード方法については、「サンプルおよびチュートリアル」を参照してください。

この記事では、.NET Core プロジェクトのテストについて説明します。 ASP.NET Core プロジェクトをテストしている場合は、「ASP.NET Core の統合テスト」を参照してください。

必須コンポーネント

ソース プロジェクトを作成する

シェル ウィンドウを開きます。 ソリューションを保存するための unit-testing-using-mstest というディレクトリを作成します。 この新しいディレクトリ内で dotnet new sln を実行して、クラス ライブラリとテスト プロジェクト用の新しいソリューション ファイルを作成します。 PrimeService ディレクトリを作成します。 現時点のディレクトリとファイルの構造は次のアウトラインのようになっています。

/unit-testing-using-mstest
    unit-testing-using-mstest.sln
    /PrimeService

PrimeService を現在のディレクトリにし、dotnet new classlib を実行してソース プロジェクトを作成します。 Class1.cs の名前を PrimeService.cs に変更します。 ファイル内のコードを次のコードに置き換えると、PrimeService クラスの、エラーが発生する実装が作成されます。

using System;

namespace Prime.Services
{
    public class PrimeService
    {
        public bool IsPrime(int candidate)
        {
            throw new NotImplementedException("Please create a test first.");
        }
    }
}

unit-testing-using-mstest ディレクトリに戻ります。 dotnet sln add を実行して、クラス ライブラリ プロジェクトをソリューションに追加します。

dotnet sln add PrimeService/PrimeService.csproj

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

PrimeService.Tests ディレクトリを作成します。 次の一覧はディレクトリ構造を示したものです。

/unit-testing-using-mstest
    unit-testing-using-mstest.sln
    /PrimeService
        Source Files
        PrimeService.csproj
    /PrimeService.Tests

PrimeService.Tests ディレクトリを現在のディレクトリにします。それから dotnet new mstest を利用して新しいプロジェクトを作成します。 dotnet new コマンドによって、テスト ライブラリとして MSTest を使用するテスト プロジェクトが作成されます。 テンプレートで、PrimeServiceTests.csproj ファイルのテスト ランナーが構成されます。

<ItemGroup>
  <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
  <PackageReference Include="MSTest.TestAdapter" Version="2.1.1" />
  <PackageReference Include="MSTest.TestFramework" Version="2.1.1" />
  <PackageReference Include="coverlet.collector" Version="1.3.0" />
</ItemGroup>

テスト プロジェクトには、単体テストを作成して実行するための、他のパッケージが必要です。 前の手順では、dotnet new によって、MSTest SDK、MSTest テスト フレームワーク、MSTest ランナー、およびコード カバレッジ レポート用の Coverlet が追加されました。

プロジェクトに別の依存関係として PrimeService クラス ライブラリを追加します。 dotnet add reference コマンドを使用する。

dotnet add reference ../PrimeService/PrimeService.csproj

全体のファイルは GitHub のサンプル リポジトリで確認できます。

ソリューションの最終的なレイアウトは次のアウトラインのようになります。

/unit-testing-using-mstest
    unit-testing-using-mstest.sln
    /PrimeService
        Source Files
        PrimeService.csproj
    /PrimeService.Tests
        Test Source Files
        PrimeServiceTests.csproj

unit-testing-using-mstest ディレクトリに移動して、dotnet sln add を実行します。

dotnet sln add ./PrimeService.Tests/PrimeService.Tests.csproj

最初のテストを作成する

失敗するテストを作成してそれを合格させる、というプロセスを繰り返します。 PrimeService.Tests ディレクトリから UnitTest1.cs を削除し、PrimeService_IsPrimeShould.cs という名前の新しい C# ファイルを作成します。コンテンツは次のようになります。

using Microsoft.VisualStudio.TestTools.UnitTesting;
using Prime.Services;

namespace Prime.UnitTests.Services
{
    [TestClass]
    public class PrimeService_IsPrimeShould
    {
        private readonly PrimeService _primeService;

        public PrimeService_IsPrimeShould()
        {
            _primeService = new PrimeService();
        }

        [TestMethod]
        public void IsPrime_InputIs1_ReturnFalse()
        {
            bool result = _primeService.IsPrime(1);

            Assert.IsFalse(result, "1 should not be prime");
        }
    }
}

TestClass 属性は、単体テストを含むクラスを表します。 TestMethod 属性は、メソッドがテスト メソッドであることを示します。

このファイルを保存し、dotnet test を実行してテストとクラス ライブラリをビルドしてから、テストを実行します。 MSTest テスト ランナーには、テストを実行するためのプログラムのエントリ ポイントが含まれています。 dotnet test を実行すると、作成した単体テスト プロジェクトを使用してテスト ランナーが開始されます。

テストが失敗します。 実装はまだ作成していません。 最も単純な動作のコードを PrimeService クラスに記述して、このテストが成功するようにします。

public bool IsPrime(int candidate)
{
    if (candidate == 1)
    {
        return false;
    }
    throw new NotImplementedException("Please create a test first.");
}

unit-testing-using-mstest ディレクトリで、もう一度 dotnet test を実行します。 dotnet test コマンドは PrimeService プロジェクトのビルドを実行してから、PrimeService.Tests プロジェクトのビルドを実行します。 両方のプロジェクトをビルドすると、この単一テストが実行されます。 成功します。

その他の機能を追加する

テストが成功したので、他のテストも記述してみましょう。 素数に関する、いくつかの単純なケースが他にもあります (0、-1)。 TestMethod 属性を使用すると新しいテストを追加できますが、すぐに煩雑になります。 一連の類似のテストを記述できるようになる、他の MSTest 属性があります。 テスト メソッドでは、異なる入力引数を持つ同じコードを実行できます。 DataRow 属性を使用して、そのような入力の値を指定することができます。

新しいテストを作成するのではなく、この 2 つの属性を適用することで 1 つのデータ駆動テストを作成できます。 そのデータ駆動テストとは、複数の 2 未満の値を調べて、最も小さい素数を特定するという手法です。 PrimeService_IsPrimeShould.cs に新しいテスト メソッドを追加します。

[TestMethod]
[DataRow(-1)]
[DataRow(0)]
[DataRow(1)]
public void IsPrime_ValuesLessThan2_ReturnFalse(int value)
{
    var result = _primeService.IsPrime(value);

    Assert.IsFalse(result, $"{value} should not be prime");
}

dotnet test を実行して、これらの 2 つのテストが失敗したとします。 すべてのテストを成功させるために、PrimeService.cs ファイルで IsPrime メソッドの先頭にある if 句を変更します。

if (candidate < 2)

他のテスト、理論、コードをメイン ライブラリに追加して、反復を続けます。 テストの最終版ができ、ライブラリの完全な実装が完了しました。

これで、小さなライブラリとそのライブラリの単体テストのセットが構築されました。 ソリューションを構築したことで、新しいパッケージとテストの追加が通常のワークフローに組み込まれました。 アプリケーションの目標を達成することに時間と労力の多くを割き、集中して取り組みました。

関連項目