次の方法で共有


データ駆動型単体テストを作成する

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

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

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

テスト対象のメソッド

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

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

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

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

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

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

ここでは、ループを使用して 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 属性を使用して、データ ドリブン テストで使用されるデータを提供するメンバーの名前、種類、および定義型 (既定では現在の型が使用されます) を指定します。

メモ

MSTest 3.8 より前の DynamicDataSourceType 列挙型には、PropertyMethodの 2 つのメンバーがありました。 既定値は Propertyでした。 MSTest 3.8 以降では、新しいメンバー AutoDetect が列挙型に追加され、既定値になります。 そのため、DynamicDataSourceTypeを指定する必要はなくなりました。

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});
}

DynamicDataDisplayName 属性の DynamicData プロパティを使用して、既定で生成される表示名をオーバーライドすることもできます。 表示名メソッドの署名は 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 インデクサー プロパティを使用して、テストで使用する値を取得します。

メモ

DataSourceAttribute は現在、.NET Framework でのみサポートされています。 .NET Core、.NET 5 以降、UWP、または WinUI 単体テスト プロジェクトでこのメソッドを使用してテスト データにアクセスしようとすると、"'TestContext' に 'DataRow' の定義が含まれていないため、'TestContext' 型の最初の引数を受け取るアクセス可能な拡張メソッド 'DataRow' が見つかりません (using ディレクティブまたはアセンブリ参照がありませんか)" のようなエラーが表示されます。"

データ ソースを作成する

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

FirstNumber SecondNumber 合計
0 1 1
1 1 2
2 -3 -1

テスト クラスに TestContext を追加する

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

public TestContext TestContext { get; set; }

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

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

AddIntegers 用のテスト メソッドはかなりシンプルです。 データ ソース内の各行に対して、パラメーターとして AddIntegers 列値と SecondNumber 列値を持つ を呼び出し、その戻り値を 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"]);

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

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

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

メモ

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

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

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