dotnet テストと xUnit を使用した .NET での単体テスト C#

このチュートリアルでは、単体テスト プロジェクトとソース コード プロジェクトが含まれるソリューションを構築する方法を示します。 構築済みのソリューションを使用してチュートリアルに従う場合は、サンプル コードを表示またはダウンロードしてください。 ダウンロード方法については、「サンプルおよびチュートリアル」を参照してください。

ソリューションを作成する

このセクションでは、ソース プロジェクトとテスト プロジェクトを含むソリューションが作成されます。 完成したソリューションのディレクトリ構造は次のようになります。

/unit-testing-using-dotnet-test
    unit-testing-using-dotnet-test.sln
    /PrimeService
        PrimeService.cs
        PrimeService.csproj
    /PrimeService.Tests
        PrimeService_IsPrimeShould.cs
        PrimeServiceTests.csproj

テスト ソリューションを作成する手順を次に示します。 テスト ソリューションをワンステップで作成する手順については、テスト ソリューションを作成するためのコマンドに関する記事を参照してください。

  • シェル ウィンドウを開きます。

  • 次のコマンドを実行します。

    dotnet new sln -o unit-testing-using-dotnet-test
    

    dotnet new sln コマンドによって、unit-testing-using-dotnet-test ディレクトリに新しいソリューションが作成されます。

  • ディレクトリを unit-testing-using-dotnet-test フォルダーに変更します。

  • 次のコマンドを実行します。

    dotnet new classlib -o PrimeService
    

    dotnet new classlib コマンドによって、PrimeService フォルダーに新しいクラス ライブラリ プロジェクトが作成されます。 この新しいクラス ライブラリに、テスト対象のコードが含まれることになります。

  • Class1.cs の名前を PrimeService.cs に変更します。

  • PrimeService.cs のコードを、次のコードに置き換えます。

    using System;
    
    namespace Prime.Services
    {
        public class PrimeService
        {
            public bool IsPrime(int candidate)
            {
                throw new NotImplementedException("Not implemented.");
            }
        }
    }
    
  • 上記のコードでは次の操作が行われます。

    • 実装されていないことを示すメッセージを含む NotImplementedException がスローされます。
    • このチュートリアルの中で、後で更新します。
  • unit-testing-using-dotnet-test ディレクトリで、次のコマンドを実行して、クラス ライブラリ プロジェクトをソリューションに追加します。

    dotnet sln add ./PrimeService/PrimeService.csproj
    
  • 次のコマンドを実行して、PrimeService.Tests プロジェクトを作成します。

    dotnet new xunit -o PrimeService.Tests
    
  • 上記のコマンドにより、次のことが行われます。

    • PrimeService.Tests ディレクトリに PrimeService.Tests プロジェクトが作成されます。 このテスト プロジェクトでは、テスト ライブラリとして xUnit が使用されます。
    • プロジェクト ファイルに次の <PackageReference /> 要素を追加することで、テスト ランナーを構成します。
      • Microsoft.NET.Test.Sdk
      • xunit
      • xunit.runner.visualstudio
      • coverlet.collector
  • 次のコマンドを実行して、ソリューション ファイルにテスト プロジェクトを追加します。

    dotnet sln add ./PrimeService.Tests/PrimeService.Tests.csproj
    
  • PrimeService.Tests プロジェクトへの依存関係として PrimeService クラス ライブラリを追加します。

    dotnet add ./PrimeService.Tests/PrimeService.Tests.csproj reference ./PrimeService/PrimeService.csproj  
    

ソリューションを作成するためのコマンド

このセクションでは、前のセクション内のすべてのコマンドの概要を示します。 前のセクションの手順を完了している場合は、このセクションをスキップしてください。

次のコマンドによって、Windows コンピューター上にテスト ソリューションが作成されます。 macOS と Unix の場合は、ren コマンドを ren の OS バージョンに更新してファイルの名前を変更します。

dotnet new sln -o unit-testing-using-dotnet-test
cd unit-testing-using-dotnet-test
dotnet new classlib -o PrimeService
ren .\PrimeService\Class1.cs PrimeService.cs
dotnet sln add ./PrimeService/PrimeService.csproj
dotnet new xunit -o PrimeService.Tests
dotnet add ./PrimeService.Tests/PrimeService.Tests.csproj reference ./PrimeService/PrimeService.csproj
dotnet sln add ./PrimeService.Tests/PrimeService.Tests.csproj

前のセクションの「PrimeService.cs 内のコードを次のコードに置き換える」の指示に従います。

テストを作成する

テスト駆動開発 (TDD) の一般的なアプローチは、ターゲット コードを実装する前に(失敗した)テストを記述することです。 このチュートリアルでは、この TDD アプローチを使用します。 IsPrime メソッドは呼び出し可能ですが、実装されていません。 IsPrime のテスト呼び出しは失敗します。 TDD では、失敗することがわかっているテストを記述します。 テストに合格するように、ターゲット コードを更新します。 このアプローチを繰り返して、失敗するテストを記述した後、テストに合格するようにターゲット コードを更新します。

PrimeService.Tests プロジェクトを更新します。

  • PrimeService.Tests/UnitTest1.cs を削除します。
  • PrimeService.Tests/PrimeService_IsPrimeShould.cs ファイルを作成します。
  • PrimeService_IsPrimeShould.cs のコードを、次のコードに置き換えます。
using Xunit;
using Prime.Services;

namespace Prime.UnitTests.Services
{
    public class PrimeService_IsPrimeShould
    {
        [Fact]
        public void IsPrime_InputIs1_ReturnFalse()
        {
            var primeService = new PrimeService();
            bool result = primeService.IsPrime(1);

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

[Fact] 属性で、テスト ランナーによって実行されるテスト メソッドを宣言します。 PrimeService.Tests フォルダーから、dotnet test を実行します。 dotnet test コマンドで、両方のプロジェクトをビルドし、テストを実行します。 xUnit テスト ランナーには、テストを実行するためのプログラムのエントリ ポイントが含まれています。 dotnet test で、単体テスト プロジェクトを使用するテスト ランナーが開始されます。

IsPrime が実装されていないため、テストは失敗します。 TDD アプローチでは、このテストに合格するのに十分なコードだけを記述します。 次のコードを使用して IsPrime を更新します。

public bool IsPrime(int candidate)
{
    if (candidate == 1)
    {
        return false;
    }
    throw new NotImplementedException("Not fully implemented.");
}

dotnet test を実行します。 テストに合格します。

さらにテストを追加する

0 と -1 のための素数テストを追加します。 前の手順で作成したテストをコピーし、次のコードをコピーして 0 と -1 をテストすることはできます。 ただし、それは行わないでください。もっと良い方法があります。

var primeService = new PrimeService();
bool result = primeService.IsPrime(1);

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

パラメーターだけを変更するときにテスト コードをコピーすると、コードの重複が発生してテストが膨張します。 次の xUnit 属性を使用して、類似する一連のテストを記述できます。

  • [Theory] は同じコードを実行するものの、異なる入力引数が含まれる一連のテストを表します。
  • [InlineData] 属性は、これらの入力の値を指定します。

新しいテストを作成するのではなく、上記の xUnit 属性を適用することで、単一の理論を作成できます。 以下のコードを

[Fact]
public void IsPrime_InputIs1_ReturnFalse()
{
    var primeService = new PrimeService();
    bool result = primeService.IsPrime(1);

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

次のコードに置き換えます。

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

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

上記のコードでは、[Theory][InlineData] によって、2 未満のいくつかの値をテストできます。 2 は最小の素数です。

クラス宣言の後、[Theory] 属性の前に次のコードを追加します。

private readonly PrimeService _primeService;

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

dotnet test を実行します。2 つのテストが失敗します。 すべてのテストに合格するようにするには、次のコードで IsPrime メソッドを更新します。

public bool IsPrime(int candidate)
{
    if (candidate < 2)
    {
        return false;
    }
    throw new NotImplementedException("Not fully implemented.");
}

TDD アプローチに従って、失敗するテストをさらに追加した後、ターゲット コードを更新します。 テストの最終版と、ライブラリの完全な実装を参照してください。

完成した IsPrime メソッドは、素数性をテストするための効率的なアルゴリズムではありません。

その他の技術情報