Tabellendatenquelle
Stellen Sie sicher, dass Sie mit der grundlegenden Ausführung von TAEF vertraut sind und wissen, wie Sie Tests erstellen können, bevor Sie mit diesem Abschnitt fortfahren.
Nachdem Sie nun grundlegende Testautomatisierung geschrieben und mit TAEF arbeiten, können Sie sich auf Szenarien konzentrieren, in denen derselbe Testcode verwendet werden kann, um an unterschiedlichen Datensätzen zu arbeiten. Zu diesem Zweck bietet TAEF einen tabellenbasierten Ansatz für datengesteuerte Tests. Sehen wir uns ein einfaches Beispiel an, um zu verstehen, wie Sie einen datengesteuerten Test erstellen.
Betrachten Sie ein einfaches, nicht datengesteuertes Beispiel, in dem Sie die Größe und das Design in die Konsole drucken. In dieser Übung konvertieren Sie diesen Test in einen datengesteuerten Test.
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 */
Definieren der Daten
Nun möchten Sie, dass die obige Funktion für eine Reihe von Größen und Designs funktioniert. Mit anderen Worten, Sie möchten Variantendatenwerte, die unsere Funktion nutzen kann. Um dies zu tun, definieren Sie zwei Tabellen in einer XML-Datei DataDrivenTests.xml:
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>
Sie haben nun zwei Tabellen definiert, "Table1" und "Table2". Sie können Tabellen für mehrere Testmethoden in derselben XML-Datei definieren.
Beachten Sie, dass Sie in Table1 die ParameterTypes im Voraus definiert und "Size" als ganze Zahl ausgewählt haben. Der Abschnitt ParameterTypes ist optional. Wenn keine Parametertypinformationen bereitgestellt werden, werden sie standardmäßig als Zeichenfolge gespeichert. Dies ist für alle Parameter in "Table2" der Fall.
Jede "Zeile", die in einer Tabelle definiert wird, ist ein Satz von Datenwerten (Parameterwerten), die von der Testfunktion akzeptiert werden sollen. Die Zeilen 9, 14 und 19 definieren 3 Datensätze, die von der FirstTable-Funktion akzeptiert werden. In ähnlicher Weise definieren die Zeilen 26, 30 und 34 die Datasets für SecondTable.
Beachten Sie die Zeilen 9, 14, 19, 26, 30 und 34 im obigen Beispiel. Sie können Zeilenspezifische Metadaten definieren. Es gibt jetzt eine Möglichkeit, dass Metadateninformationen mit Datasets für dieselbe Funktion geändert werden können. Die Priorität für den ersten Datensatz (Zeile 9) ist 1, die Priorität für den zweiten Datensatz (Zeile 14) ist 2, und der dritte Datensatz (Zeile 19) ist standardmäßig auf die Priorität der Funktion festgelegt. Alle Zeilen erben die Metadaten von der Funktion, der die Tabelle zugeordnet ist. Wenn dieselben Metadaten auf Zeilenebene erneut angegeben werden, werden die metadatenspezifischen Werte überschrieben, die auf Funktionsebene definiert sind.
HINWEIS: Die XML-Dateischemadefinition ist sowohl für nativen als auch für verwalteten Code identisch, mit Ausnahme der unterstützten Typdefinitionen. Im ersten Teil des Abschnitts "Managed Data Driven Test" unten finden Sie ein weiteres Beispiel für die Definition der Daten. Fahren Sie mit Native Data Driven Test fort, um die in nativem Code zulässigen Typen zu verstehen.
Native Datengesteuerter Test
Da die Datasets definiert und für den Verbrauch bereit sind, benötigen Sie jetzt eine Möglichkeit, die Testfunktion als datengesteuerten Test zu qualifizieren und sie der Tabelle zuzuordnen, die das Dataset definiert. Dies geschieht durch zusätzliche Metadaten beim Erstellen des Tests:
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 */
Um die XML-Tabelle dem Test zuzuordnen, fügen Sie der Methode des Tests die Metadaten "DataSource" hinzu. Über diese Zuordnung verwendet TAEF die angegebene Datenquelle, um den Test zu steuern. Der DataSource-Wert umfasst drei Teile:
- 'Table:' – Dadurch wird die Datenquelle als XML-Tabelle identifiziert.
- "DataDrivenTests.xml": Dies ist die Datei, die die XML-Tabelle enthält.
- "#Table2": Nach dem Delimeter "#" identifiziert der Wert "Table2" die bestimmte Tabelle im zu verwendenden XML-Dokument. Eine einzelne XML-Tabellendatenquelle kann mehrere Tabellen enthalten. TAEF sucht die XML-Datei nach einem Table-Element mit einem Attribut "Id", das dem angegebenen Wert entspricht.
Möglicherweise haben Sie im obigen Beispiel beobachtet, dass "SecondTable" vor "FirstTable" definiert ist. Dies bedeutet, dass die Funktion "SecondTable" vor der Funktion "FirstTable" ausgeführt wird, aber Sie haben "Table1" definiert, die Tabelle, die "FirstTable" entspricht, vor "Table2", der Tabelle, die "SecondTable" entspricht. Dadurch soll hervorgehoben werden, dass die Reihenfolge der Tabellendefinition während der Ermittlung und Ausführung der datengesteuerten Tests irrelevant ist.
Nachdem die Zuordnung unserer Datenquelle zur Testmethode abgeschlossen ist, können Sie das Beispiel ändern, um die Daten aus der Quelle abzurufen. Bevor Sie dies tun, sehen Sie sich die veröffentlichte Headerdatei TestData.h an. Der Teil des Interesses ist:
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 };
Zeile 5 zeigt die API an, die aufgerufen werden soll, um die Daten in der Funktion abzurufen. Sehen Sie sich die verfügbaren Parametertypen für den Abruf an.
Ok – alles so festgelegt, dass unser Beispiel neu geschrieben wird:
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 */
Zeilen 7 und 18 sind die Standard Teile, die geändert wurden, um die Testdaten zu fahren. Keine große Veränderung. Sehen Sie sich das Ausführen von datengesteuerten Tests an, um zu verstehen, wie Sie TAEF beim Ausführen von datengesteuerten Tests optimal nutzen können.
Verwaltete datengesteuerte Tests
Betrachten Sie ein Beispiel, in dem Sie die Koordinaten eines Rechtecks auf der Konsole drucken möchten. Beginnen Sie mit der Definition dieser Koordinaten als Dataset in einer XML-Datei.
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>
Definieren Sie das Dataset im Bereich einer Tabelle, in diesem Fall "FirstTable", der oben in Zeile 3 definiert ist. Sie können Tabellen für mehrere Testmethoden in derselben XML-Datei definieren.
Beachten Sie, dass FirstTable die ParameterTypes im Voraus definiert und "Left" als "Int32" ausgibt. Der Abschnitt ParameterTypes ist optional. Wenn keine Parametertypinformationen bereitgestellt werden, werden sie standardmäßig als Zeichenfolge gespeichert.
Sehen Sie sich die Liste der unterstützten Parametertypen an.
Wenn ein anderer Datentyp angegeben wird, löst der Test eine Warnung aus und betrachtet ihn als Zeichenfolge.
HINWEIS: Bei den Typzeichenfolgen wird die Groß-/Kleinschreibung nicht beachtet, sollte jedoch genau wie oben dargestellt geschrieben werden.
Jede "Zeile", die in einer Tabelle definiert ist, ist ein Satz von Datenwerten (Parameterwerten), die von der Testfunktion akzeptiert werden sollen. Die Zeilen 10, 16 und 22 definieren 3 Datensätze, die unsere Funktion enthalten.
Beachten Sie die Zeilen 10, 16 und 22 im obigen Beispiel. Sie können Zeilenspezifische Metadaten definieren. Sie haben jetzt die Möglichkeit, Metadateninformationen mit Datasets für dieselbe Funktion zu ändern. Die Priorität für den ersten Datensatz (Zeile 10) ist 1, die Priorität für den zweiten Datensatz (Zeile 16) ist 2, und der dritte Datensatz (Zeile 22) ist standardmäßig auf die Priorität der Funktion festgelegt. Alle Zeilen erben die Metadaten von der Funktion, der die Tabelle zugeordnet ist. Wenn dieselben Metadaten auf Zeilenebene erneut angegeben werden, werden die metadatenspezifischen Werte überschrieben, die auf Funktionsebene definiert sind.
HINWEIS: Die XML-Dateischemadefinition ist sowohl für nativen als auch für verwalteten Code identisch, mit Ausnahme der unterstützten Typdefinitionen. Sehen Sie sich den Abschnitt "Definieren der Daten" oben auf dieser Seite an, um ein weiteres Beispiel dafür zu finden, wie Sie dies definieren.
Jetzt haben Sie alle Daten definiert. Das folgende Beispiel zeigt, wie Sie darauf zugreifen.
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 }
Das Zuordnen der XML-Tabelle zu einer bestimmten Testmethode in verwaltetem Code ähnelt sehr dem nativen Code. Wenden Sie einfach die Metadaten "DataSource" an. Wie bisher besteht es aus drei Teilen:
- "Table:", um die Datenquelle als XML-Tabelle zu identifizieren.
- "CSharpDataDrivenTests.xml" – die Datei, die die XML-Tabelle enthält.
- "#FirstTable" – Nach dem Delimeter "#" identifiziert der Wert "FirstTable" die bestimmte Tabelle im zu verwendenden XML-Dokument. TAEF sucht die XML-Datei nach einem Table-Element mit einem Attribut "Id", das dem angegebenen Wert entspricht.
Beachten Sie, dass die Second-Funktion nicht datengesteuert ist. Sie können sich dafür entscheiden, dass nur einige Ihrer Tests datengesteuert werden. Sie haben auch die Möglichkeit, für jeden Test seine Tabelle in einer anderen XML-Datei zu definieren.
In Zeile 36 definieren Sie eine private TestContext-Eigenschaft, wie VSTS die TestContext-Klasse empfiehlt. Sie definieren auch öffentliche Bewertungen für diese Eigenschaft (Zeilen 30 bis 34). Intern lädt TAEF die Wörterbucheigenschaft von TestContext mit dem entsprechenden Dataset im Fokus.
TestContext ist in Microsoft.VisualStudio.TestTools.UnitTesting definiert. Siehe Zeile 3 im obigen Beispiel. Sie sollten dies bereits als Referenz in Ihre verwaltete Testerstellung einschließen. Daher sind keine zusätzlichen Verweise zum Erstellen von datengesteuerten Tests erforderlich.
In Zeile 18 des obigen Beispiels zeigen Sie, wie Daten in der Funktion abgerufen werden. Beachten Sie, dass die Daten in m_testContext.DataRow verfügbar sind.
Name statt Index zum Identifizieren eines DataRow
TAEF ermöglicht es Ihnen, eine aussagekräftigere "Name"-Eigenschaft anstelle des Index zu verwenden, um dataRow in Ihrer Datenquelle zu identifizieren. Fügen Sie dazu einfach "Name"-Metadaten auf Zeilenebene in Ihrer DataSource hinzu. Unser erstes Beispiel auf dieser Seite kann wie folgt geändert werden, um dieses Feature zu verwenden:
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>
Im obigen geänderten Beispiel entspricht "BlueTransparent" dem Index 0. Die Zeile mit Index 1 hat keinen speziellen Namen, und die Zeile mit Index 2 hat den Namen "BlackTransparent". Sie können weiterhin eine Auswahlabfrage verwenden, um nach Index 0 oder 2 in "Table1" zu suchen, und es wird die richtige Zeile gefunden. Aber beim Ausführen oder Auflisten der DLL, anstatt Folgendes anzuzeigen:
<qualified name of the test method>#<index>
Stattdessen wird Folgendes angezeigt:
<qualified name of the test method>#<name property provided at Row level>
für die Zeilen, bei denen das Attribut "Name" auf Zeilenebene bereitgestellt wird. Wenn die Eigenschaft "Name" für keine Zeile bereitgestellt wird, wie im Fall von Index 1 oben, wird standardmäßig #<index> am qualifizierten Namen der Methode verwendet.
Beachten Sie, dass Sie durch die Bereitstellung eines "Name"-Attributs auf Zeilenebene im Wesentlichen die Art und Weise ändern, wie TAEF den Namen des instance des Methodenaufrufs mit den entsprechenden Row-Daten interpretiert.
DataSource als Runtime-Parameter
TAEF unterstützt die Bereitstellung der Datenquelle als Laufzeitparameter. Die Syntax hierfür sieht wie folgt aus:
te <test dll names> /p:<DataSource runtime name>=Table:<DataSoure XML file>#<Table Id>
Bei der Erstellung des betroffenen Tests müssen Sie den "p:<DataSource-Laufzeitnamen>" als Datenquelle angeben. Beachten Sie, dass Sie zur Laufzeit die vollständige Zeichenfolge angeben müssen – den XML-Dateinamen und die Tabellen-ID zusammen. Es wird nicht erwartet, dass die TableId als Testmetadaten bereitgestellt wird, wenn Ihre Datenquelle zur Laufzeit bereitgestellt wird. Das Präfix "Table:" gibt an, dass Sie nach einer Tabellendatenquelle suchen.
Sie können dies mit einem der Auf der Releasefreigabe verfügbaren Beispiele ausprobieren:
te Examples\CPP.RuntimeDataSource.Example.dll /p:MyDataSource=Table:RuntimeDataSourceExample.xml#SimpleTable
DataSource als Ressource
Mit TAEF können Sie Ihre DataSource als Ressource Ihres Testmoduls hinzufügen, sofern sie folgendes erfüllt:
Bei nativen Testmodulen können Sie dies tun, indem Sie Ihre DataSource als Ressourcen-ID oder Ressourcennamen angeben. Hier finden Sie ein Codebeispiel:
BEGIN_TEST_METHOD(ResourceNameDataSource)
TEST_METHOD_PROPERTY(L"DataSource", L"Table:MyResourceName#SimpleTable")
END_TEST_METHOD()
"MyResourceName" ist der Ressourcenname, der in der Datei ResourceDataSource.rc in diesem Fall definiert ist:
MyResourceName DATASOURCE_XML "ResourceDataSource.xml"
Bei verwalteten Testmodulen kann die Ressource nur auf eine bestimmte Weise angegeben werden, wie im unten gezeigten Quelldateiausschnitt :
LANGUAGE_NEUTRAL_MANAGED_RESOURCES = CSharpAdvancedDataDrivenTests.xml
Die DataSource-Metadatenspezifikation bleibt unverändert, wenn die DataSource-XML-Datei angegeben wird. Ähnlich wie bei verwaltetem Code können Sie den Ressourcennamen mit dem XML-Dateinamen identisch machen. Es ist daher wichtig zu verstehen, dass TAEF zuerst nach dem Vorhandensein der tatsächlichen Datei mit dem DataSource-Namen sucht. Wenn eine solche XML-Datei nicht gefunden wird, wird nur dann mit der Suche nach einer Testressource im Testmodul mit dem angegebenen Ressourcennamen oder der angegebenen ID fortzufahren. Da die Angabe der DataSource als Ressource eine erneute Kompilierung erfordert, können Sie diesen Entwurf nutzen, indem Sie die DataSource-XML-Datei während der Entwicklung an den gleichen Speicherort wie die Test-DLL kopieren (und den Ressourcennamen mit dem XML-Dateinamen benennen). Kopieren Sie nach Abschluss des Tests den XML-Code zurück in das Codeverzeichnis, und kompilieren Sie sie als Ressource neu. Vergessen Sie nicht, die XML-Datei aus dem Ausführungsverzeichnis zu löschen! :)
Beispiel für exemplarische Vorgehensweisen
Um verschiedene Aspekte tabellenbasierter datengesteuerter Tests zu verstehen, lesen Sie einige weitere exemplarische Vorgehensweisen: