データ ドリブン単体テストを作成する

マネージド コード用の Microsoft 単体テスト フレームワーク (MSTest) を使用し、データ ソースから値を取得する単体テスト メソッドを設定できます。 メソッドはデータ ソース内の各行に対して連続して実行されるため、単一のメソッドを使用してさまざまな入力を簡単にテストできます。

データ ドリブン単体テストでは、次のいずれかの種類を使用できます。

  • インライン データ (DataRow 属性を使用)
  • メンバー データ (DynamicData 属性を使用)
  • 既知のソース プロバイダーから (DataSource 属性を使用)

テスト対象のメソッド

たとえば、次が用意されています。

  1. さまざまな種類の勘定のトランザクションを受け入れて処理する MyBank というソリューション。

  2. 勘定のトランザクションを管理する BankDb という MyBank 内のプロジェクト。

  3. トランザクションが必ず銀行にとって有利になるように数値演算関数を実行する BankDb プロジェクト内の Maths というクラス。

  4. BankDb コンポーネントの動作をテストする BankDbTests という単体テスト プロジェクト。

  5. Maths クラスの動作を確認する MathsTests という単体テスト クラス。

ループを使用して 2 つの整数を追加する Maths のメソッドをテストします。

public int AddIntegers(int first, int second)
{
    int sum = first;
    for (int i = 0; i < second; i++)
    {
        sum += 1;
    }

    return sum;
}

テスト メソッドをテストする

インラインのデータ ドリブン テスト

インライン テストの場合、MSTest では DataRow を使って、データ ドリブン テストで使用される値を指定します。 この例のテストは、データ行ごとに連続して実行されます。

[TestMethod]
[DataRow(1, 1, 2)]
[DataRow(2, 2, 4)]
[DataRow(3, 3, 6)]
[DataRow(0, 0, 1)] // The test run with this row fails
public void AddIntegers_FromDataRowTest(int x, int y, int expected)
{
    var target = new Maths();
    int actual = target.AddIntegers(x, y);
    Assert.AreEqual(expected, actual,
        "x:<{0}> y:<{1}>",
        new object[] {x, y});
}

メンバーのデータ ドリブン テスト

MSTest では DynamicData 属性を使って、データ ドリブン テストで使用されるデータを提供するメンバーの名前、種類 (プロパティ、既定値、またはメソッド)、定義する型 (既定では現在の型が使用されます) を指定します。

public static IEnumerable<object[]> AdditionData
{
    get
    {
        return new[]
        { 
            new object[] { 1, 1, 2 },
            new object[] { 2, 2, 4 },
            new object[] { 3, 3, 6 },
            new object[] { 0, 0, 1 }, // The test run with this row fails
        };
    }
}

[TestMethod]
[DynamicData(nameof(AdditionData))]
public void AddIntegers_FromDynamicDataTest(int x, int y, int expected)
{
    var target = new Maths();
    int actual = target.AddIntegers(x, y);
    Assert.AreEqual(expected, actual,
        "x:<{0}> y:<{1}>",
        new object[] {x, y});
}

DynamicData 属性の DynamicDataDisplayName プロパティを使用して、既定で生成される表示名をオーバーライドすることもできます。 表示名メソッドのシグネチャは public static string であり、2 つのパラメーター (1 つ目が MethodInfo 型、2 つ目が object[] 型) を受け取る必要があります。

public static string GetCustomDynamicDataDisplayName(MethodInfo methodInfo, object[] data)
{
    return string.Format("DynamicDataTestMethod {0} with {1} parameters", methodInfo.Name, data.Length);
}

[DynamicData(nameof(AdditionData), DynamicDataDisplayName = nameof(GetCustomDynamicDataDisplayName))]

ソース プロバイダーのデータ ドリブン テスト

データ ソース ドリブン単体テストを作成するには、次の手順を実行します。

  1. テスト メソッドで使用する値を含むデータ ソースを作成します。 データ ソースは、テストを実行するコンピューターに登録されている任意の型にすることができます。

  2. TestContext 型のパブリック TestContext プロパティをテスト クラスに追加します。

  3. 単体テスト メソッドを作成します

  4. それに DataSourceAttribute 属性を追加します。

  5. DataRow インデクサー プロパティを使用して、テストで使用する値を取得します。

データ ソースを作成する

AddIntegers メソッドをテストするには、パラメーターの値の範囲と返される必要のある合計を指定するデータ ソースを作成します。 この例では、MathsData という名前の Sql Compact データベースと、次の列の名前と値を含む AddIntegersData という名前のテーブルを作成します

FirstNumber SecondNumber SUM
0 1 1
1 1 2
2 -3 -1

テスト クラスへの TestContext の追加

単体テスト フレームワークは、データ ドリブン テストのデータ ソース情報を格納する TestContext オブジェクトを作成します。 次に、フレームワークは作成する TestContext プロパティの値としてこのオブジェクトを設定します。

public TestContext TestContext { get; set; }

テスト メソッドでは、TestContextDataRow インデクサー プロパティを使用してデータにアクセスします。

Note

.NET Core では DataSource 属性がサポートされていません。 .NET Core、UWP、または WinUI 単体テスト プロジェクトでこの方法でテスト データにアクセスしようとすると、"'TestContext' に 'DataRow' の定義が含まれておらず、型 'TestContext' の最初の引数を受け付けるアクセス可能な拡張メソッド 'DataRow' が見つかりませんでした。using ディレクティブまたはアセンブリ参照が不足していないことを確認してください" のようなエラーが表示されます。

テスト メソッドの記述

AddIntegers のテスト メソッドは非常に単純です。 データ ソース内の各行に対して、パラメーターとして FirstNumber 列値と SecondNumber 列値を持つ AddIntegers を呼び出して、Sum 列値に対して戻り値を確認します。

[TestMethod]
[DataSource(@"Provider=Microsoft.SqlServerCe.Client.4.0; Data Source=C:\Data\MathsData.sdf;", "Numbers")]
public void AddIntegers_FromDataSourceTest()
{
    var target = new Maths();

    // Access the data
    int x = Convert.ToInt32(TestContext.DataRow["FirstNumber"]);
    int y = Convert.ToInt32(TestContext.DataRow["SecondNumber"]);
    int expected = Convert.ToInt32(TestContext.DataRow["Sum"]);
    int actual = target.AddIntegers(x, y);
    Assert.AreEqual(expected, actual,
        "x:<{0}> y:<{1}>",
        new object[] {x, y});
}

DataSourceAttribute の指定

DataSource 属性は、データ ソースの接続文字列とテスト メソッドで使用するテーブル名を指定します。 接続文字列の正確な情報は、使用しているデータ ソースの種類によって異なります。 この例では、SqlServerCe データベースを使用しました。

[DataSource(@"Provider=Microsoft.SqlServerCe.Client.4.0;Data Source=C:\Data\MathsData.sdf", "AddIntegersData")]

注意事項

接続文字列には、機密データ (パスワードなど) を含めることができます。 接続文字列は、ソース コードのプレーン テキストおよびコンパイル済みアセンブリに格納されます。 この機密情報を保護するために、ソース コードとアセンブリへのアクセスを制限します。

DataSource 属性には 3 つのコンストラクターがあります。

[DataSource(dataSourceSettingName)]

1 つのパラメーターを持つコンストラクターは、ソリューションの app.config ファイルに格納されている接続情報を使用します。 dataSourceSettingsName は、接続情報を指定する構成ファイル内の Xml 要素の名前です。

app.config ファイルを使用すると、単体テスト自体に変更を加えずに、データ ソースの場所を変更できます。 app.config ファイルの作成および使用方法の詳細については、「チュートリアル: データ ソースを定義するための構成ファイルの使用」を参照してください

[DataSource(connectionString, tableName)]

2 つのパラメーターを持つ DataSource コンストラクターは、データ ソースの接続文字列とテスト メソッドのデータを含むテーブルの名前を指定します。

接続文字列は、データ ソースの種類によって異なりますが、データ プロバイダーの不変名を指定する Provider 要素を含んでいる必要があります。

[DataSource(
    dataProvider,
    connectionString,
    tableName,
    dataAccessMethod
    )]

データにアクセスするための TestContext.DataRow の使用

AddIntegersData テーブル内のデータにアクセスするには、TestContext.DataRow インデクサーを使用します。 DataRow は、DataRow オブジェクトであるため、インデックスまたは列の名前で列の値を取得します。 値はオブジェクトとして返されるため、適切な型に変換します。

int x = Convert.ToInt32(TestContext.DataRow["FirstNumber"]);

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

テスト メソッドの記述が完了したら、テスト プロジェクトを構築します。 [テストを実行しない] グループのテスト エクスプローラーに、テスト メソッドが表示されます。 テストを実行して、記述し、再実行すると、テスト エクスプローラー[失敗したテスト][成功したテスト][テストを実行しない] のグループの結果が表示されます。 [すべて実行] を選択してテストをすべて実行することも、 [実行] を選択してテストのサブセットを実行することもできます。

テストの実行中は、テスト エクスプローラーの上部にあるテスト結果バーがアニメーションで表示されます。 テストの実行の終了時に、すべてのテストが成功した場合はバーが緑色になり、いずれかのテストが失敗した場合は赤色になります。 テスト エクスプローラー ウィンドウの下部の詳細ウィンドウに、テストの実行の概要が表示されます。 テストを選択すると、そのテストの詳細が下部のペインに表示されます。

Note

データの各行に対する結果と、1 つのサマリー結果もあります。 データの各行のテストが合格すると、サマリー実行は [合格] と表示されます。 いずれかのデータ行のテストが失敗すると、サマリー実行は [失敗] と表示されます。

この例で AddIntegers_FromDataRowTestAddIntegers_FromDynamicDataTest、または AddIntegers_FromDataSourceTest メソッドのいずれかを実行した場合、結果バーが赤に変わり、テスト メソッドは [失敗したテスト] に移動します。 データ ソースからの反復されたメソッドのいずれかが失敗した場合は、データ ドリブン テストは失敗します。 テスト エクスプローラー ウィンドウで、失敗したデータ ドリブン テストを選択すると、詳細ウィンドウにはデータ行インデックスによって識別される各イテレーションの結果が表示されます。 この例では、AddIntegers アルゴリズムが負の値を正しく処理していないことがわかります。

テスト対象のメソッドを修正して、テストを再実行すると、結果バーが緑に変わり、テスト メソッドは [成功したテスト] グループに移動されます。