テーブルのデータ ソース
このセクションに進む前に、TAEF の基本的な実行と、それを使用してテストを作成する方法を理解していることを確認してください。
TAEF を使用して基本的なテスト自動化を記述し、操作できるようになったら、同じテスト コードを使用してさまざまなデータ セットを処理するシナリオに集中できます。 このために、TAEF ではデータ ドリブン テストの "テーブル ベースの" アプローチを提供しています。 データ ドリブン テストの作成方法を理解するために、簡単な例を見てみましょう。
サイズとテーマをコンソールに出力する単純な非データ ドリブンの例について考えてみましょう。 この演習では、このテストをデータ ドリブン テストに変換します。
1 namespace WEX { namespace TestExecution { namespace Examples
2 {
3 void DataDrivenTests::FirstTable()
4 {
5 int size = 12;
6 Log::Comment(String().Format(L"Size retrieved was %d", size));
7 }
8
9 void DataDrivenTests::SecondTable()
10 {
11 String theme = "Aero";
12 Log::Comment(L"Theme supplied as " + theme);
13 }
14 } /* namespace Examples */ } /* namespace TestExecution */ } /* namespace WEX */
データの定義
上記の関数が一連のサイズとテーマで機能するようにします。 つまり、関数で使用できるバリアント データ値が必要です。 そのために、DataDrivenTests.xml という XML ファイルで 2 つのテーブルを定義します。
1 <?xml version="1.0"?>
2 <Data>
3 <Table Id ="Table1">
4 <ParameterTypes>
5 <ParameterType Name="Size">Int32</ParameterType>
6 <ParameterType Name="Color">String</ParameterType>
7 <ParameterType Name="Transparency">Boolean</ParameterType>
8 </ParameterTypes>
9 <Row Priority="1" Owner="C2">
10 <Parameter Name="Size">12</Parameter>
11 <Parameter Name="Color">Blue</Parameter>
12 <Parameter Name="Transparency">True</Parameter>
13 </Row>
14 <Row Priority="2" Owner="wex">
15 <Parameter Name="Size">4</Parameter>
16 <Parameter Name="Color">White</Parameter>
17 <Parameter Name="Transparency">False</Parameter>
18 </Row>
19 <Row Owner="C2">
20 <Parameter Name="Size">9</Parameter>
21 <Parameter Name="Color">Black</Parameter>
22 <Parameter Name="Transparency">True</Parameter>
23 </Row>
24 </Table>
25 <Table id ="Table2">
26 <Row Description="ButtonTest" Owner="C2" Priority="1">
27 <Parameter Name="Control">Button</Parameter>
28 <Parameter Name="Theme">Aero</Parameter>
29 </Row>
30 <Row Description="ComboBoxTest" Priority="2">
31 <Parameter Name="Control">ComboBox</Parameter>
32 <Parameter Name="Theme">Classic</Parameter>
33 </Row>
34 <Row Description="ListviewTest" Owner="wex">
35 <Parameter Name="Control">Listview</Parameter>
36 <Parameter Name="Theme">AeroBasic</Parameter>
37 </Row>
38 </Table>
39 </Data>
これで、"Table1" と "Table2" の 2 つのテーブルが定義されました。 同じ XML ファイルで、複数のテスト メソッドのテーブルを定義できます。
Table1 では、ParameterTypes を事前に定義し、"Size" に整数を指定していることに注意してください。 ParameterTypes セクションは省略可能です。 既定では、パラメーターの型情報が指定されていない場合、文字列として保存されます。 これは、"Table2" のすべてのパラメーターに当てはまります。
テーブル内で定義されている各 "Row" は、テスト関数が受け入れる一連のデータ (パラメーター) 値です。 9 行目、14 行目、19 行目では、FirstTable 関数が受け入れる 3 つのデータ セットを定義しています。 同様に、26 行目、30 行目、34 行目では、SecondTable のデータ セットを定義しています。
上記の例の 9 行目、14 行目、19 行目、26 行目、30 行目、34 行目に注目してください。その Row に固有のメタデータを定義できます。 同じ関数のデータ セットでメタデータ情報を変更できるようになりました。 最初のデータ セット (9 行目) の優先度は 1、2 番目のデータ セット (14 行目) の優先度は 2 です。3 番目のデータ セット (19 行目) は、既定で関数の優先度に設定されます。 すべての行は、テーブルが関連付けられている関数からメタデータを継承します。 同じメタデータが行レベルで再度指定された場合、関数レベルで定義されたメタデータ値がオーバーライドされます。
注: XML ファイルのスキーマ定義は、サポートされている型定義を除き、ネイティブ コードでもマネージド コードでも同じです。 データを定義する方法の別の例については、後述の「マネージド データ ドリブン テスト」の最初の部分を参照してください。 ネイティブ コードで使用できる型を理解するには、「ネイティブ データ ドリブン テスト」に進んでください。
ネイティブ データ ドリブン テスト
データ セットを定義し、使用する準備ができたら、テスト関数をデータ ドリブン テストと見なし、データ セットを定義するテーブルに関連付ける方法が必要になります。 これを行うには、テストの作成時に追加のメタデータを使用します。
1 namespace WEX { namespace TestExecution { namespace Examples
2 {
3 class DataDrivenTests
4 {
5 TEST_CLASS(DataDrivenTests);
6
7 BEGIN_TEST_METHOD(SecondTable)
8 TEST_METHOD_PROPERTY(L"DataSource", L"Table:DataDrivenTests.xml#Table2")
9 TEST_METHOD_PROPERTY(L"Priority", L"3")
10 END_TEST_METHOD()
11
12 BEGIN_TEST_METHOD(FirstTable)
13 TEST_METHOD_PROPERTY(L"Priority", L"4")
14 TEST_METHOD_PROPERTY(L"DataSource", L"Table:DataDrivenTests.xml#Table1")
15 END_TEST_METHOD()
16 };
17 } /* namespace Examples */ } /* namespace TestExecution */ } /* namespace WEX */
XML テーブルをテストに関連付けるために、"DataSource" メタデータをテストのメソッドに追加します。 この関連付けにより、TAEF は指定された DataSource を使用してテストを実行します。 DataSource 値は、次の 3 つの部分で構成されます。
- "Table:" - データ ソースが XML テーブルであることを示します。
- "DataDrivenTests.xml" - XML テーブルを含むファイルです。
- "#Table2" - "#" 区切り記号の後の "Table2" 値は、使用する XML ドキュメント内の特定のテーブルを識別します。 1 つの XML テーブル データ ソースに複数のテーブルを含めることができます。 TAEF は XML ファイルを調べて、'Id' 属性が指定された値と一致する Table 要素を探します。
上記の例では、"FirstTable" の前に "SecondTable" が定義されていることにお気付きかもしれません。 これは、"FirstTable" 関数の前に "SecondTable" 関数が実行されることを意味します。しかし、"FirstTable" に対応するテーブルである "Table1" は、"SecondTable" に対応するテーブルである "Table2" の前に定義しました。 これは、データ ドリブン テストの検出および実行時には、テーブル定義の順序は関係ないことを強調するためです。
テスト メソッドへのデータ ソースのマッピングが完了したので、ソースからデータを取得するように、この例を変更できるようになりました。 その前に、発行されたヘッダー ファイル (TestData.h) を見てみましょう。 興味深い部分を次に示します。
1 class TestData
2 {
3 public:
4 template <typename T>
5 static HRESULT __stdcall TryGetValue(_In_z_ const wchar_t* pszString, T& result)
6 {
7 return Private::TestData<T>::TryGetValue(pszString, result);
8 }
9 };
5 行目は、関数内のデータを取得するために呼び出す API を示しています。 取得可能なパラメーターの型を確認してください。
これで、この例を書き換える準備ができました。
1 namespace WEX { namespace TestExecution { namespace Examples
2 {
3 void DataDrivenTests::FirstTable()
4 {
5 Log::Comment(L"I am in first table");
6 int size;
7 if (SUCCEEDED(TestData::TryGetValue(L"size", size)))
8 {
9 VERIFY_ARE_NOT_EQUAL(size, 0);
10 Log::Comment(String().Format(L"Size retrieved was %d", size));
11 }
12 }
13
14 void DataDrivenTests::SecondTable()
15 {
16 Log::Comment(L"I am in second table.");
17 String theme;
18 if (SUCCEEDED(TestData::TryGetValue(L"theme", theme)))
19 {
20 Log::Comment(L"Theme supplied as " + theme);
21 }
22 }
23 } /* namespace Examples */ } /* namespace TestExecution */ } /* namespace WEX */
7 行目と 18 行目が、テストをデータ ドリブンにするために変更された主要部分です。 大きな変更ではありません。 データ ドリブン テストの実行中に TAEF を最大限に活用する方法については、「データ ドリブン テストの実行」を参照してください。
マネージド データ ドリブン テスト
四角形の座標をコンソールに出力する例を考えてみましょう。 まず、XML ファイルでこれらの座標をデータ セットとして定義します。
1 <?xml version="1.0"?>
2 <Data>
3 <Table Id="FirstTable">
4 <ParameterTypes>
5 <ParameterType Name="Left">Int32</ParameterType>
6 <ParameterType Name="Right">String</ParameterType>
7 <ParameterType Name="Top">Integer</ParameterType>
8 <ParameterType Name="Bottom">Int32</ParameterType>
9 </ParameterTypes>
10 <Row Priority="1" Owner="C2" Description="Zero rect">
11 <Parameter Name="Left">0</Parameter>
12 <Parameter Name="Right">0</Parameter>
13 <Parameter Name="Top">0</Parameter>
14 <Parameter Name="Bottom">0</Parameter>
15 </Row>
16 <Row Priority="2" Owner="wex" Description="normal rect">
17 <Parameter Name="Left">12</Parameter>
18 <Parameter Name="Right">25</Parameter>
19 <Parameter Name="Top">10</Parameter>
20 <Parameter Name="Bottom">50</Parameter>
21 </Row>
22 <Row Owner="C2" Description="invalid rect">
23 <Parameter Name="Left">30</Parameter>
24 <Parameter Name="Right">15</Parameter>
25 <Parameter Name="Top">40</Parameter>
26 <Parameter Name="Bottom">10</Parameter>
27 </Row>
28 </Table>
29 </Data>
テーブル (この例では、上記の 3 行目で定義されている "FirstTable") のスコープでデータ セットを定義します。 同じ XML ファイルで、複数のテスト メソッドのテーブルを定義できます。
FirstTable では、ParameterTypes を事前に定義し、"Left" に "Int32" を指定していることがわかります。 ParameterTypes セクションは省略可能です。 既定では、パラメーターの型情報が指定されていない場合、文字列として保存されます。
サポートされているパラメーターの型の一覧を参照してください。
他のデータ型が指定されている場合、テストで警告がスローされ、文字列と見なされます。
注: 型の文字列では大文字と小文字は区別されませんが、スペルは上記のとおりにする必要があります。
テーブル内で定義されている各 "Row" は、テスト関数が受け入れる一連のデータ (パラメーター) 値です。 10 行目、16 行目、22 行目では、関数が受け入れる 3 つのデータ セットを定義しています。
上記の例の 10 行目、16 行目、22 行目に注目してください。Row に固有のメタデータを定義できます。 同じ関数のデータ セットでメタデータ情報を変更できるようになりました。 最初のデータ セット (10 行目) の優先度は 1、2 番目のデータ セット (16 行目) の優先度は 2 です。3 番目のデータ セット (22 行目) は、既定で関数の優先度に設定されます。 すべての行は、テーブルが関連付けられている関数からメタデータを継承します。 同じメタデータが行レベルで再度指定された場合、関数レベルで定義されたメタデータ値がオーバーライドされます。
注: XML ファイルのスキーマ定義は、サポートされている型定義を除き、ネイティブ コードでもマネージド コードでも同じです。 これを定義する方法の別の例については、このページの冒頭にある「データの定義」を参照してください。
これで、すべてのデータが定義されました。 次の例は、データにアクセスする方法を示しています。
1 namespace WEX.Examples
2 {
3 using Microsoft.VisualStudio.TestTools.UnitTesting;
4 using System;
5 using System.Collections;
6 using WEX.Logging.Interop;
7 using WEX.TestExecution;
8
9 [TestClass]
10 public class CSharpDataDrivenTests
11 {
12 [TestMethod]
15 [DataSource("Table:CSharpDataDrivenTests.xml#FirstTable")]
16 public void First()
17 {
18 Console.WriteLine("Left is " + m_testContext.DataRow["Left"].ToString());
19
20 Log.Comment("In CSharpDataDrivenTests.First");
21 }
22
23 [TestMethod]
24 public void Second()
25 {
26 Log.Comment("In CSharpDataDrivenTests.Second");
27 Verify.IsTrue(true);
28 }
29
30 public TestContext TestContext
31 {
32 get { return m_testContext; }
33 set { m_testContext = value; }
34 }
35
36 private TestContext m_testContext;
37 }
38 }
マネージド コードでの XML テーブルと特定のテスト メソッドの関連付けは、ネイティブ コードとよく似ています。"DataSource" メタデータを適用するだけです。 前と同様に、DataSource は次の 3 つの部分で構成されています。
- "Table:" - データ ソースが XML テーブルであることを示します。
- "CSharpDataDrivenTests.xml" - XML テーブルを含むファイルです。
- "#FirstTable" - "#" 区切り記号の後の "FirstTable" 値は、使用する XML ドキュメント内の特定のテーブルを識別します。 TAEF は XML ファイルを調べて、'Id' 属性が指定された値と一致する Table 要素を探します。
Second 関数はデータ ドリブンではないことに注意してください。 一部のテストだけをデータ ドリブンにすることもできます。 また、各テストのテーブルを別の XML ファイルで定義することもできます。
36 行目では、プライベート TestContext プロパティが定義されています。VSTS と同様に、TestContext クラスが推奨されます。 また、このプロパティのパブリック アセッサーも定義されています (30 行目から 34 行目)。 内部的には、TAEF は対応するデータ セットに焦点を合わせて TestContext のディクショナリ プロパティを読み込みます。
TestContext は、Microsoft.VisualStudio.TestTools.UnitTesting で定義されています。 上記の例の 3 行目を参照してください。 マネージド テストの作成時に、これを参照として既に含めています。 そのため、データ ドリブン テストを作成する際に追加の参照は不要です。
上記の例の 18 行目では、関数内のデータを取得する方法を示しています。 データは m_testContext.DataRow で使用できます。
インデックスの代わりに名前を使用した DataRow の識別
TAEF では、インデックスの代わりにわかりやすい "Name" プロパティを使用して、DataSource の DataRow を識別できます。 これを行うには、DataSource の Row レベルで "Name" メタデータを追加するだけです。 このページの最初の例を次のように変更して、この機能を使用できます。
1 <?xml version="1.0"?>
2 <Data>
3 <Table id ="Table1">
4 <ParameterTypes>
5 <ParameterType Name="Size">Int32</ParameterType>
6 <ParameterType Name="Color">String</ParameterType>
7 <ParameterType Name="Transparency">Boolean</ParameterType>
8 </ParameterTypes>
9 <Row Name='BlueTransparent' Priority="1" Owner="C2">
10 <Parameter Name="Size">12</Parameter>
11 <Parameter Name="Color">Blue</Parameter>
12 <Parameter Name="Transparency">True</Parameter>
13 </Row>
14 <Row Priority="2" Owner="wex">
15 <Parameter Name="Size">4</Parameter>
16 <Parameter Name="Color">White</Parameter>
17 <Parameter Name="Transparency">False</Parameter>
18 </Row>
19 <Row Name='BlackTransparent' Owner="C2">
20 <Parameter Name="Size">9</Parameter>
21 <Parameter Name="Color">Black</Parameter>
22 <Parameter Name="Transparency">True</Parameter>
23 </Row>
24 </Table>
25 ...
39 </Data>
上記の変更された例では、"BlueTransparent" がインデックス 0 に対応しています。 インデックス 1 の Row には特別な名前は指定されておらず、インデックス 2 の Row には "BlackTransparent" という名前が関連付けられています。 選択クエリを使用して、"Table1" のインデックス 0 または 2 を探すこともでき、正しい行が見つかります。 ただし、dll を実行または一覧表示する場合は、次のように表示されるのではなく、
<qualified name of the test method>#<index>
次のように表示されます。
<qualified name of the test method>#<name property provided at Row level>
これは、"Name" 属性が Row レベルで指定されている Row の場合です。 上記のインデックス 1 の場合のように、Row に "Name" プロパティが指定されていない場合、メソッドの修飾名で #<index> が既定で使用されます。
Row レベルで "Name" 属性を指定することで、対応する Row データを使用したメソッド呼び出しのインスタンスの名前を TAEF が解釈する方法を基本的に変更することになる点に注意してください。
ランタイム パラメーターとしての DataSource
TAEF では、ランタイム パラメーターとしてのデータソースの指定をサポートしています。 これに関する構文は次のようになります。
te <test dll names> /p:<DataSource runtime name>=Table:<DataSoure XML file>#<Table Id>
この方法でテストを作成するときには、データソースとして "p:<DataSource runtime name>" を指定する必要があります。 実行時に完全な文字列 (XML ファイル名とテーブル ID の組み合わせ) を指定する必要があることに注意してください。 データソースが実行時に提供される場合、TableId がテスト メタデータとして提供されることはありません。 "Table:" プレフィックスは、テーブル データ ソースを探していることを示しています。
リリース共有で利用できる例のいずれかを使用して、これを試すことができます。
te Examples\CPP.RuntimeDataSource.Example.dll /p:MyDataSource=Table:RuntimeDataSourceExample.xml#SimpleTable
リソースとしての DataSource
TAEF では、以下に準拠していれば、DataSource をテスト モジュールのリソースとして追加できます。
ネイティブ テスト モジュールの場合、これを行うには、リソース ID またはリソース名として DataSource を指定します。 コード例はこちらです。
BEGIN_TEST_METHOD(ResourceNameDataSource)
TEST_METHOD_PROPERTY(L"DataSource", L"Table:MyResourceName#SimpleTable")
END_TEST_METHOD()
"MyResourceName" は、この例の ResourceDataSource.rc ファイルで定義されているリソース名です。
MyResourceName DATASOURCE_XML "ResourceDataSource.xml"
マネージド テスト モジュールの場合、次の sources ファイル スニペットに示すように、リソースは特定の方法でのみ指定できます。
LANGUAGE_NEUTRAL_MANAGED_RESOURCES = CSharpAdvancedDataDrivenTests.xml
DataSource メタデータの指定は、DataSource XML ファイルを指定する場合と変わりはありません。 マネージド コードの場合と同様に、リソース名を XML ファイル名と同じにすることができます。 そのため、TAEF は DataSource 名が付けられた実際のファイルが存在するかどうかを最初に調べることを理解しておく必要があります。 そのような XML ファイルが見つからない場合にのみ、指定されたリソース名または ID でテスト モジュール内のテスト リソースの検索が続行されます。DataSource をリソースとして指定するには再コンパイルが必要であるため、開発時 (およびリソース名を XML ファイル名と同じにするとき) に、DataSource XML ファイルをテスト dll と同じ場所にコピーすることで、この設計を利用できます。 テストが完了したら、XML をコード ディレクトリにコピーし、リソースとして再コンパイルします。 実行ディレクトリから XML ファイルを削除するのを忘れないでください。 :)
サンプル チュートリアル
テーブル ベースのデータ ドリブン テストのさまざまな側面を把握するために、他のサンプル チュートリアルも参照してください。