単体テストの基本

コードが予想どおりに動作することを確認するには、単体テストを作成して実行します。 単体テストと呼ばれる理由は、プログラムの機能を、個々の 単体としてテストできる独立したテスト可能な動作に分解するためです。 Visual Studio テスト エクスプローラーには、Visual Studio で単体テストを実行して結果を表示するための柔軟で効率的な方法が用意されています。 Visual Studio と共に、マネージド コードおよびネイティブ コード用の Microsoft 単体テスト フレームワークがインストールされます。 単体テスト フレームワーク を使用して、単体テストを作成して実行し、テストの結果を報告します。 変更を加えたときは単体テストを再実行し、コードが正しく機能するかテストします。 Visual Studio Enterprise では、Live Unit Testing でこれを自動化できます。この機能は、コード変更で影響のあったテストを検出し、ユーザーが入力している間にバックグラウンドで実行します。

単体テストは、ソフトウェア開発ワークフローの構成要素になったときに、コードの品質に最大の効果をもたらします。 関数またはその他のアプリケーション コードを記述したらすぐに、標準的な入力データ、境界上のデータ、および正しくないデータに対するコードの動作を検証し、コードによる明示的または暗黙的な前提を確認する単体テストを作成してください。 テスト駆動開発では、コードを記述する前に単体テストを作成することで、設計ドキュメントと機能仕様の両方として単体テストを使用します。

テスト エクスプローラーは、テスト エクスプローラーのアドオン インターフェイスを実装した、サードパーティ製やオープン ソースの単体テスト フレームワークも実行できます。 Visual Studio 拡張機能マネージャーおよび Visual Studio ギャラリーを使用して、これらのフレームワークの多くを追加できます。 詳細については、「サードパーティ製の単体テスト フレームワークをインストールする」をご覧ください。

コードから簡単にテスト プロジェクトとテスト メソッドを生成したり、必要に応じて手動でテストを作成したりできます。 IntelliTest を使用して .NET コードを精査する際は、テスト データと単体テストのスイートを生成できます。 コードにある各ステートメントについて、そのステートメントを実行するテスト入力が生成されます。 .NET コードの単体テストを生成する方法をご覧ください。

はじめに

コーディングに直接関係する単体テストの概要については、次のいずれかのトピックを参照してください。

Bank ソリューションの例

この記事では、例として MyBank という架空のアプリケーションの開発を使用します。 このトピックの説明は、実際のコードがなくても理解できます。 テスト メソッドは C# で記述されており、マネージド コード用の Microsoft 単体テスト フレームワークを使用して提供されます。 ただし、その概念は他の言語やフレームワークに簡単に移行することができます。

MyBank Solution 2019

MyBank Solution 2022

MyBank アプリケーションのデザイン時の最初の計画には、個々のアカウントおよびアカウントの銀行との取引を表すアカウント コンポーネントと、個々のアカウントを集計および管理する機能を表すデータベース コンポーネントが含まれます。

次の 2 つのプロジェクトを含む Bank ソリューションを作成します。

  • Accounts

  • BankDB

Accounts プロジェクトのデザイン時の最初の計画には、アカウントに関する基本情報を保持するクラス、アカウントでの資産の預け入れや引き出しなど、任意の種類のアカウントの共通機能を指定するインターフェイス、および当座預金アカウントを表すインターフェイスから派生したクラスが含まれます。 次のソース ファイルを作成して、Accounts プロジェクトを開始します。

  • AccountInfo.cs は、アカウントの基本情報を定義します。

  • IAccount.cs は、アカウントで資産の預け入れや引き出しを行うメソッドや、アカウントの残高を取得するメソッドを含む、アカウントの標準の IAccount インターフェイスを定義します。

  • CheckingAccount.cs には、当座預金アカウントの IAccount インターフェイスを実装する CheckingAccount クラスが含まれています。

当座預金アカウントからの引き出しの際は、引き出される金額がアカウントの残高より少ないことを確認する必要があります。 そのため、この条件をチェックするメソッドで、 IAccount.WithdrawCheckingAccount メソッドをオーバーライドします。 メソッドは次のようになります。

public void Withdraw(double amount)
{
    if(m_balance >= amount)
    {
        m_balance -= amount;
    }
    else
    {
        throw new ArgumentException(nameof(amount), "Withdrawal exceeds balance!");
    }
}

少しコードがあるので、テストしましょう。

単体テスト プロジェクトとテスト メソッドを作成する (C#)

C# については、ほとんどの場合、コードから単体テスト プロジェクトと単体テスト スタブを生成する方が手軽です。 また、必要に応じて単体テスト プロジェクトとテストを手動で作成することもできます。 サード パーティ製のフレームワークでコードから単体テストを作成する場合は、拡張機能 NUnit または xUnit のいずれかをインストールする必要があります。 C# を使用していない場合、このセクションをスキップし、「単体テスト プロジェクトと単体テストを手動で作成する」に進んでください。

単体テスト プロジェクトと単体テスト スタブを生成する

  1. コード エディター ウィンドウで、右クリックして右クリック メニューから [単体テストの作成] を選択します。

    From the editor window, view the context menu

    Note

    [単体テストの作成] メニュー コマンドは、C# コードに対してのみ使用できます。 .NET Core または .NET Standard でこのメソッドを使用するには、Visual Studio 2019 以降が必要です。

    From the editor window, view the context menu

    Note

    [単体テストの作成] メニュー コマンドは、C# コードに対してのみ使用できます。 .NET Core または .NET Standard でこのメソッドを使用するには、Visual Studio 2019 以降が必要です。

  2. [OK] をクリックして、既定値をそのまま使用して単体テストを作成するか、単体テスト プロジェクトと単体テストの作成と名前付けに使用される値を変更します。 単体テスト メソッドに既定で追加されるコードを選択することができます。

    Create Unit Tests dialog box in Visual Studio

    Create Unit Tests dialog box in Visual Studio

  3. 新しい単体テスト プロジェクトでは、クラス内のすべてのメソッドに単体テスト スタブが作成されます。

    The unit tests are created

    The unit tests are created

  4. ここで、先に進み、単体テストを有意義なものにするためのテストを作成する方法と、コードを徹底的にテストするために追加する追加の単体テストについて確認します。

単体テスト プロジェクトと単体テストを手動で作成する

通常、単体テスト プロジェクトは 1 つのコード プロジェクトの構造を反映します。 MyBank の例で、2 つの単体テスト プロジェクト AccountsTests および BankDbTestsBank ソリューションに追加します。 テスト プロジェクトの名前は任意ですが、標準の名前付け規則を採用することをお勧めします。

単体テスト プロジェクトをソリューションに追加するには

  1. ソリューション エクスプローラーで、ソリューションを右クリックして、[追加]>[新しいプロジェクト] の順に選択します。

  2. プロジェクト テンプレートの検索ボックスに「テスト」と入力して、使用するテスト フレームワーク用の単体テスト プロジェクト テンプレートを検索します。 (このトピックの例では、MSTest を使用します。)

  3. 次のページでは、プロジェクトに名前を付けます。 この例の Accounts プロジェクトをテストするために、プロジェクトの名前を AccountsTestsに設定します。

  4. この例の単体テスト プロジェクトで、テスト対象のコード プロジェクトへの参照を Accounts プロジェクトに追加します。

    コード プロジェクトへの参照を作成する方法は次のとおりです。

    1. ソリューション エクスプローラーの単体テスト プロジェクトで、[参照] または [依存関係] ノードを右クリックし、[プロジェクト参照の追加] または [参照の追加] (使用可能ないずれか) を選択します。

    2. [参照マネージャー] ダイアログ ボックスで、[ソリューション] ノードを開き、[プロジェクト] を選択します。 コード プロジェクトの名前を選択し、ダイアログ ボックスを閉じます。

各単体テスト プロジェクトには、コード プロジェクト内のクラス名を反映したクラスが含まれています。 この例では、 AccountsTests プロジェクトに次のクラスが含まれています。

  • AccountInfoTests クラスには、 AccountInfo プロジェクトの Accounts クラス用の単体テスト メソッドが含まれています。

  • CheckingAccountTests クラスには、 CheckingAccount クラス用の単体テスト メソッドが含まれています。

テストを作成する

使用する単体テスト フレームワークと Visual Studio IntelliSense に従って、コード プロジェクトの単体テスト用コードを記述していきます。 ほとんどのフレームワークでは、テスト エクスプローラーで実行するには、単体テスト メソッドを識別する特定の属性を追加する必要があります。 フレームワークには、テスト メソッドが成功したか失敗したかを示す手段も用意されています。通常は、Assert ステートメントまたはメソッドの属性を使用します。 他の属性は、各テスト メソッドの前でクラスの初期化時に実行される省略可能な設定メソッド、および各テスト メソッドの後でクラスが破棄される前に実行される終了処理メソッドを識別します。

AAA (Arrange、Act、Assert) のパターンが、テスト対象のメソッドの単体テストを記述する一般的な方法です。

  • 単体テスト メソッドの Arrange セクションでは、オブジェクトを初期化し、テスト対象のメソッドに渡されるデータの値を設定します。

  • Act セクションでは、設定されたパラメーターでテスト対象のメソッドを呼び出します。

  • Assert セクションでは、テスト対象のメソッドの操作が予測どおりに動作することを検証します。 .NET では、多くの場合、Assert クラスのメソッドが検証に使用されます。

この例の CheckingAccount.Withdraw メソッドをテストするために、2 つのテストを記述できます。メソッドの標準動作を検証するテストと、残高を超える引き出しが失敗することを検証するテストです (次のコードは、.NET でサポートされる、MSTest 単体テストを示しています。)。 CheckingAccountTests クラスで、次のメソッドを追加します。

[TestMethod]
public void Withdraw_ValidAmount_ChangesBalance()
{
    // arrange
    double currentBalance = 10.0;
    double withdrawal = 1.0;
    double expected = 9.0;
    var account = new CheckingAccount("JohnDoe", currentBalance);

    // act
    account.Withdraw(withdrawal);

    // assert
    Assert.AreEqual(expected, account.Balance);
}

[TestMethod]
public void Withdraw_AmountMoreThanBalance_Throws()
{
    // arrange
    var account = new CheckingAccount("John Doe", 10.0);

    // act and assert
    Assert.ThrowsException<System.ArgumentException>(() => account.Withdraw(20.0));
}

Microsoft 単体テスト フレームワークの詳細については、次のトピックのいずれかを参照してください。

単体テストのタイムアウトを設定する

MSTest フレームワークを使用している場合、TimeoutAttribute を使用して、個々のテスト メソッドにタイムアウトを設定できます。

[TestMethod]
[Timeout(2000)]  // Milliseconds
public void My_Test()
{ ...
}

許容される最大のタイムアウトを設定するには

[TestMethod]
[Timeout(TestTimeout.Infinite)]  // Milliseconds
public void My_Test ()
{ ...
}

テスト エクスプローラーでテストを実行する

テスト プロジェクトをビルドすると、テストはテスト エクスプローラーに表示されます。 テスト エクスプローラーが表示されない場合は、Visual Studio メニューの [テスト] を選び、[Windows][テスト エクスプローラー] の順に選択します (または Ctrl + ET キーを押します)。

Unit Test Explorer

Unit Test Explorer

テストを実行して、記述し、再実行すると、テスト エクスプローラーでは、[失敗したテスト][成功したテスト][スキップされたテスト][テストを実行しない] のグループの結果を表示できます。 ツールバーのオプションで別のグループを選択できます。

グローバル レベルで検索ボックスでテキストを照合して、または定義済みのフィルターの 1 つを選択して、任意のビューでテストにフィルターを適用することもできます。 任意に選択したテストをいつでも実行できます。 テスト実行の結果は、エクスプローラー ウィンドウの上部にある成功/失敗ステータス バーですぐにわかります。 テストを選択すると、そのテスト メソッドの結果の詳細が表示されます。

テストを実行して表示する

テスト エクスプローラーのツール バーは、対象にするテストを検出、編成、実行するのに役立ちます。

Run tests from the Test Explorer toolbar

Run tests from the Test Explorer toolbar

[すべて実行] を選択して (または Ctrl + RV キーを押して) テストをすべて実行することも、[実行] を選択してテストのサブセットを実行することもできます (Ctrl + RT キー)。 テストを選択すると、そのテストの詳細がテスト詳細ペインに表示されます。 右クリック メニューから [テストを開く] を選択し (キーボード:F12 キー)、選択したテストのソース コードを表示します。

個々のテストに実行順序を定める依存関係がない場合、ツール バーの設定メニューで並列テストの実行を有効にします。 これにより、すべてのテスト実行にかかる時間を著しく短縮できます。

各ビルドの後にテストを実行する

各ローカル ビルドの後で単体テストを実行するには、テスト エクスプローラーのツール バーで設定アイコンを開き、 [ビルド後にテストを実行] を選択します。

テスト リストのフィルター処理とグループ化を実行する

多数のテストがある場合、テスト エクスプローラーの検索ボックスに入力し、指定した文字列によって一覧をフィルター処理できます。 フィルターの一覧から選択することで、フィルター イベントをさらに制限できます。

Search filter categories

Search filter categories

ボタン 説明
Test Explorer group button カテゴリ別にテストをグループ化するには、 [グループ化] をクリックします。

詳細については、「テスト エクスプローラーを使用して単体テストを実行する」を参照してください。

Q&A

Q: 単体テストのデバッグ方法を教えてください。

A:テスト エクスプローラーを使用して、テストのデバッグ セッションを開始します。 Visual Studio デバッガーを使用してコードをシームレスにステップ実行すると、テスト対象のプロジェクトと単体テストの間を切り替えることができます。 デバッグを開始するには:

  1. Visual Studio エディターで、デバッグする 1 つ以上のテスト メソッドにブレークポイントを設定します。

    注意

    テスト メソッドを任意の順序で実行できるため、デバッグするすべてのテスト メソッドにブレークポイントを設定します。

  2. テスト エクスプローラーでテスト メソッドを選択し、ショートカット メニューから [選択したテストのデバッグ] を選択します。

単体テストのデバッグの詳細を確認してください。

Q: TDD を使用している場合にテストからコードを生成する方法を教えてください。

A:クイック アクションを使用して、プロジェクト コードにクラスとメソッドを生成します。 生成するクラスまたはメソッドを呼び出すステートメントをテスト メソッドに記述し、エラーの下に表示される電球を開きます。 新しいクラスのコンストラクターへの呼び出しの場合は、メニューから [型の生成] を選択し、ウィザードに従ってコード プロジェクトにクラスを挿入します。 メソッドへの呼び出しの場合は、IntelliSense メニューから [メソッドの生成] を選択します。

Generate Method Stub Quick Action Menu

Generate Method Stub Quick Action Menu

Q: テストを実行する入力値として複数のデータ セットを使用する単体テストを作成できますか。

A: はい。 データ ドリブン テスト メソッド を使用すると、1 つの単体テスト メソッドである範囲の値をテストすることができます。 テストする変数の値が格納されているデータ ソースを指定する、テスト メソッドの DataRowDynamicData、または DataSource 属性を使用します。

属性付きメソッドは、データ ソース内の各行に対して 1 回実行されます。 イテレーションが失敗した場合、テスト エクスプローラーがメソッドのテスト失敗を報告します。 メソッドのテスト結果の詳細ペインに、データの行ごとにメソッドの成功/失敗の状態が表示されます。

データ ドリブン単体テストの詳細を確認してください。

Q: 単体テストでテストするコードの量を確認できますか。

A: はい。 Visual Studio Enterprise の Visual Studio コード カバレッジ ツールを使用し、単体テストで実際にテスト中のコードの量を確認できます。 単体テスト フレームワークによって実行できるネイティブ言語とマネージド言語、およびすべての単体テスト フレームワークがサポートされています。

選択したテストまたはソリューションのすべてのテストのコード カバレッジを実行できます。 [コード カバレッジの結果] ウィンドウに、行、関数、クラス、名前空間、およびモジュールで実行された製品コードのブロックのパーセンテージが表示されます。

ソリューション内のテスト メソッドのコード カバレッジを実行するには、[テスト]>[すべてのテストのコード カバレッジの分析] を選択します。

カバレッジの結果は、[コード カバレッジの結果] ウィンドウに表示されます。

Code coverage results

Code coverage results

コード カバレッジの詳細を確認してください。

Q: 外部依存関係を含むコード内のメソッドをテストすることはできますか。

A: はい。 Visual Studio Enterprise を使用している場合は、Microsoft Fakes は、マネージド コード用の単体テスト フレームワークを使用して記述したテスト メソッドで使用できます。

Microsoft Fakes は、次の 2 つの方法で外部依存関係の代替クラスを作成します。

  1. スタブ は、対象の依存関係クラスの親インターフェイスから派生した代替クラスを生成します。 スタブ メソッドは、対象クラスのパブリック仮想メソッドの代わりに使用できます。

  2. Shim は、ランタイム インストルメンテーションを使用して、対象メソッドへの呼び出しを仮想でないメソッドの代替 shim メソッドに転換します。

いずれの方法でも、依存関係メソッドへの呼び出しの生成されたデリゲートを使用して、テスト メソッド内の動作を指定します。

詳細については、「 Microsoft Fakes で単体テスト メソッドを分離する」を参照してください。

Q: 他の単体テスト フレームワークを使用して単体テストを作成することはできますか。

A: はい。以下の手順に従って、 他のフレームワークを検索してインストールしてください。 Visual Studio を再起動した後、単体テストを作成するためのソリューションをもう一度開き、インストールしたフレームワークを選びます。

Select other installed unit test framework

選んだフレームワークを使用して、単体テスト スタブが作成されます。