Partager via


Source de données table

Assurez-vous que vous êtes familiarisé avec l’exécution de base de TAEF et que vous savez comment créer des tests à l’aide de celle-ci, avant de passer à cette section.

Maintenant que vous avez écrit l’automatisation des tests de base et que vous utilisez TAEF, vous pouvez vous concentrer sur des scénarios où le même code de test peut être utilisé pour travailler sur différents ensembles de données. À cet effet, TAEF fournit une approche « table » pour les tests pilotés par les données. Examinons un exemple simple pour comprendre comment créer un test piloté par les données.

Prenons un exemple simple non piloté par les données dans lequel vous imprimez la taille et le thème dans la console. Dans cet exercice, vous allez convertir ce test en test piloté par les données.

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 */

Définition des données

Maintenant, vous souhaitez que la fonction ci-dessus fonctionne pour un ensemble de tailles et de thèmes. En d’autres termes, vous voulez des valeurs de données de variante que notre fonction peut consommer. Pour ce faire, définissez deux tables dans un fichier XML 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>

Vous avez maintenant défini deux tables, « Table1 » et « Table2 ». Vous pouvez définir des tables pour plusieurs méthodes de test dans le même fichier XML.

Notez que dans Table1, vous avez défini les ParameterTypes à l’avance et choisi « Size » comme entier. La section ParameterTypes est facultative. Par défaut, si les informations de type de paramètre ne sont pas fournies, elles sont enregistrées sous forme de chaîne. C’est le cas pour tous les paramètres de « Table2 ».

Chaque « ligne » définie dans une table est un ensemble de valeurs de données (paramètre) que vous souhaitez que la fonction de test accepte. Les lignes 9, 14 et 19 définissent 3 ensembles de données que notre fonction FirstTable accepterait. De même, les lignes 26, 30 et 34 définissent les jeux de données pour SecondTable.

Notez les lignes 9, 14, 19, 26, 30 et 34 dans l’exemple ci-dessus . Vous pouvez définir des métadonnées spécifiques à la ligne. Il existe maintenant un moyen pour les informations de métadonnées de changer avec les jeux de données pour la même fonction. La priorité pour le premier ensemble de données (ligne 9) est 1, la priorité pour le deuxième ensemble de données (ligne 14) est 2 et le troisième ensemble de données (ligne 19) est défini par défaut sur la priorité de la fonction. Toutes les lignes héritent des métadonnées de la fonction à laquelle la table est associée. Si les mêmes métadonnées sont à nouveau spécifiées au niveau de la ligne, les valeurs de métadonnées définies au niveau de la fonction sont remplacées.

REMARQUE : La définition de schéma de fichier XML est la même pour le code natif et managé, à l’exception des définitions de type prises en charge. Consultez la partie initiale de la section « Test piloté par les données managées » ci-dessous pour obtenir un autre exemple de définition des données. Poursuivez le test piloté par les données natives pour comprendre les types autorisés dans le code natif.

Test piloté par les données natives

Une fois les jeux de données définis et prêts à être utilisés, vous avez maintenant besoin d’un moyen de qualifier la fonction de test en tant que test piloté par les données et de l’associer à la table qui définit le jeu de données. Pour ce faire, utilisez des métadonnées supplémentaires lors de la création du test :

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 */

Pour associer la table XML au test, ajoutez les métadonnées « DataSource » à la méthode du test. Grâce à cette association, TAEF utilisera le DataSource donné pour conduire le test. La valeur DataSource comporte trois parties :

  1. 'Table:' : identifie la source de données comme étant une table XML.
  2. « DataDrivenTests.xml » : il s’agit du fichier qui contient la table XML.
  3. '#Table2' : après le délimètre '#', la valeur 'Table2' identifie la table particulière dans le document XML à utiliser. Une seule source de données Table XML peut contenir plusieurs tables. TAEF recherche dans le fichier XML un élément Table avec un attribut « Id » qui correspond à la valeur spécifiée.

Vous avez peut-être observé dans l’exemple ci-dessus que « SecondTable » est défini avant « FirstTable ». Cela signifie que la fonction « SecondTable » sera exécutée avant la fonction « FirstTable », mais que vous avez défini « Table1 », la table correspondant à « FirstTable », avant « Table2 », la table correspondant à « SecondTable ». Il s’agit de souligner que l’ordre de définition de la table n’est pas pertinent lors de la découverte et de l’exécution des tests pilotés par les données.

Une fois le mappage de notre source de données à la méthode de test terminé, vous pouvez maintenant modifier l’exemple pour obtenir les données de la source. Avant de procéder, examinez le fichier d’en-tête publié, TestData.h. La partie de l’intérêt est :

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

La ligne 5 montre l’API à appeler afin de récupérer les données dans la fonction. Examinez les types de paramètres disponibles pour la récupération.

Ok - tous définis pour réécrire notre exemple :

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 */

Les lignes 7 et 18 sont les main parties qui ont changé pour que les données de test soient pilotées. Il n’y a pas beaucoup de changement. Consultez Exécution de tests pilotés par les données pour comprendre comment tirer le meilleur parti de TAEF lors de l’exécution de tests pilotés par les données.

Test piloté par les données managées

Prenons un exemple où vous souhaitez imprimer les coordonnées d’un rectangle sur la console. Commencez par définir ces coordonnées en tant que jeu de données dans un fichier 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>

Définissez le jeu de données dans l’étendue d’une table, en l’occurrence « FirstTable », qui est définie à la ligne 3 ci-dessus. Vous pouvez définir des tables pour plusieurs méthodes de test dans le même fichier XML.

Notez que FirstTable définit les ParameterTypes à l’avance et appelle « Left » comme un « Int32 ». La section ParameterTypes est facultative. Par défaut, si les informations de type de paramètre ne sont pas fournies, elles sont enregistrées sous forme de chaîne.

Consultez la liste des types de paramètres pris en charge.

Si un autre type de données est spécifié, le test lève un avertissement et le considère comme une chaîne.

REMARQUE : Les chaînes de type ne respectent pas la casse, mais doivent être orthographiées exactement comme indiqué ci-dessus.

Chaque « Ligne » définie dans une table est un ensemble de valeurs de données (paramètre) que vous souhaitez que la fonction de test accepte. Les lignes 10, 16 et 22 définissent 3 ensembles de données que notre fonction.

Notez les lignes 10, 16 et 22 dans l’exemple ci-dessus . Vous pouvez définir des métadonnées spécifiques à Row. Vous disposez maintenant d’un moyen pour que les informations de métadonnées changent avec les jeux de données pour la même fonction. La priorité pour le premier ensemble de données (ligne 10) est 1, la priorité pour le deuxième ensemble de données (ligne 16) est 2 et le troisième ensemble de données (ligne 22) est défini par défaut sur la priorité de la fonction. Toutes les lignes héritent des métadonnées de la fonction à laquelle la table est associée. Si les mêmes métadonnées sont à nouveau spécifiées au niveau de la ligne, les valeurs de métadonnées définies au niveau de la fonction sont remplacées.

REMARQUE : La définition de schéma de fichier XML est la même pour le code natif et managé, à l’exception des définitions de type prises en charge. Consultez la section « Définition des données » en haut de cette page pour obtenir un autre exemple de définition.

À présent, vous avez défini toutes les données. L’exemple suivant montre comment y accéder.

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 }

L’association de la table XML à une méthode de test donnée dans le code managé est très similaire au code natif ; appliquez simplement les métadonnées « DataSource ». Comme auparavant, il se compose de trois parties :

  1. 'Table:' : pour identifier la source de données comme étant une table XML.
  2. 'CSharpDataDrivenTests.xml' : fichier qui contient la table XML.
  3. '#FirstTable' : après le délimètre '#', la valeur 'FirstTable' identifie la table particulière dans le document XML à utiliser. TAEF recherche dans le fichier XML un élément Table avec un attribut « Id » qui correspond à la valeur spécifiée.

Notez que la fonction Second n’est pas pilotée par les données. Vous pouvez choisir de n’avoir que certains de vos tests pour être pilotés par les données. Vous avez également la possibilité de faire en sorte que chaque test ait sa table définie dans un autre fichier XML.

À la ligne 36, vous définissez une propriété TestContext privée, comme la classe TestContext recommandée par VSTS. Vous définissez également des évaluateurs publics pour cette propriété (lignes 30 à 34). En interne, TAEF charge la propriété de dictionnaire de TestContext avec le jeu de données correspondant dans le focus.

TestContext est défini dans Microsoft.VisualStudio.TestTools.UnitTesting. Consultez la ligne 3 de l’exemple ci-dessus. Vous devez déjà l’inclure comme référence dans votre création de tests managés. Par conséquent, aucune référence supplémentaire n’est requise pour la création de tests pilotés par les données.

À la ligne 18 de l’exemple ci-dessus, vous montrez comment récupérer des données dans la fonction . Notez que les données sont disponibles dans m_testContext.DataRow.

Nom au lieu de l’index pour identifier un DataRow

TAEF vous permet d’avoir une propriété « Name » plus explicite au lieu de l’index pour identifier tout DataRow dans votre DataSource. Pour ce faire, ajoutez simplement des métadonnées « Name » au niveau ligne dans votre DataSource. Notre premier exemple de cette page peut être modifié pour utiliser cette fonctionnalité comme suit :

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>

Dans l’exemple modifié ci-dessus, « BlueTransparent » correspond à l’index 0. La ligne avec l’index 1 n’a aucun nom spécial qui lui est attribué et la ligne avec l’index 2 a le nom 'BlackTransparent qui lui est associé. Vous pouvez toujours utiliser une requête de sélection pour rechercher l’index 0 ou 2 dans « Table1 », et elle trouvera la ligne correcte. Toutefois, lors de l’exécution ou de la liste de la dll, au lieu de voir :

<qualified name of the test method>#<index>

à la place, vous verrez :

<qualified name of the test method>#<name property provided at Row level>

pour les lignes où l’attribut « Name » est fourni au niveau de la ligne. Si la propriété « Name » n’est pas fournie pour une ligne, comme dans le cas de l’index 1 ci-dessus, elle aura par défaut #<index> au nom qualifié de la méthode.

Notez qu’en fournissant un attribut « Name » au niveau de la ligne, vous modifiez essentiellement la façon dont TAEF interprète le nom du instance de l’appel de méthode avec les données Row correspondantes.

DataSource en tant que paramètre Runtime

TAEF prend en charge la fourniture de la source de données en tant que paramètre d’exécution. La syntaxe est la suivante :

te <test dll names> /p:<DataSource runtime name>=Table:<DataSoure XML file>#<Table Id>

Lors de la création du test en question, vous devez spécifier le « nom> du runtime p:<DataSource » comme source de données. N’oubliez pas que vous devez spécifier la chaîne complète (le nom du fichier XML ainsi que l’ID de table) au moment de l’exécution. Le TableId n’est pas censé être fourni en tant que métadonnées de test si votre source de données est fournie au moment de l’exécution. Le préfixe « Table: » spécifie que vous recherchez une source de données de table.

Vous pouvez l’essayer avec l’un des exemples disponibles sur le partage de mise en production :

te Examples\CPP.RuntimeDataSource.Example.dll /p:MyDataSource=Table:RuntimeDataSourceExample.xml#SimpleTable

DataSource en tant que ressource

TAEF vous permet d’ajouter votre DataSource en tant que ressource de votre module de test tant qu’il est conforme aux éléments suivants :

Dans le cas de modules de test natifs, vous pouvez le faire en spécifiant votre DataSource comme ID de ressource ou nom de ressource. Voici un exemple de code :

BEGIN_TEST_METHOD(ResourceNameDataSource)
    TEST_METHOD_PROPERTY(L"DataSource", L"Table:MyResourceName#SimpleTable")
END_TEST_METHOD()

« MyResourceName » est le nom de la ressource tel que défini dans le fichier ResourceDataSource.rc dans ce cas :

MyResourceName DATASOURCE_XML "ResourceDataSource.xml"

Dans le cas de modules de test managés, la ressource ne peut être spécifiée que d’une certaine manière, comme indiqué dans l’extrait de code de fichier source ci-dessous :

LANGUAGE_NEUTRAL_MANAGED_RESOURCES = CSharpAdvancedDataDrivenTests.xml

La spécification des métadonnées DataSource restera la même que dans le cas de la spécification du fichier XML DataSource. Comme dans le code managé, vous pouvez rendre le nom de la ressource identique au nom du fichier XML. Il est donc important de comprendre que TAEF recherche d’abord la présence du fichier réel avec le nom DataSource. Si un tel fichier XML est introuvable, ce n’est qu’alors qu’il continuera à rechercher la ressource de test dans le module de test avec le nom ou l’ID de ressource donné. Étant donné que la spécification de DataSource en tant que ressource nécessite une re-compilation, vous pouvez tirer parti de cette conception en copiant le fichier XML DataSource vers le même emplacement que la dll de test lors du développement (et en nommant le nom de la ressource comme étant le même que le nom de fichier XML). Une fois que vous avez terminé le test, copiez le code XML dans le répertoire de code et recomcompilez à nouveau en tant que ressource. N’oubliez pas de supprimer le fichier XML du répertoire d’exécution ! :)

Exemples de procédures

Pour comprendre les différents aspects des tests basés sur les données basés sur des tables, lisez quelques autres exemples de procédures :