Condividi tramite


Origine dati tabella

Assicurarsi di avere familiarità con l'esecuzione di base di TAEF e di sapere come creare test usandolo, prima di procedere con questa sezione.

Ora che è stata scritta e usata l'automazione dei test di base con TAEF, è possibile concentrarsi sugli scenari in cui è possibile usare lo stesso codice di test per lavorare su set di dati diversi. A questo scopo, TAEF offre un approccio basato su tabelle ai test basati sui dati. Di seguito viene illustrato un semplice esempio per comprendere come creare un test basato sui dati.

Si consideri un semplice esempio non basato sui dati in cui si stampano le dimensioni e il tema nella console. In questo esercizio si convertirà questo test in un test basato sui dati.

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

Definizione dei dati

Si vuole ora che la funzione precedente funzioni per un set di dimensioni e temi. In altre parole, si vogliono valori di dati varianti che la funzione può utilizzare. A tale scopo, definire due tabelle in un file 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>

Sono state definite due tabelle, "Table1" e "Table2". È possibile definire tabelle per diversi metodi di test nello stesso file XML.

Si noti che in Table1 è stato definito il parametro ParameterTypes in anticipo e si è scelto "Size" come numero intero. La sezione ParameterTypes è facoltativa. Per impostazione predefinita, se le informazioni sul tipo di parametro non vengono fornite, verranno salvate come stringa. Questo è il caso di tutti i parametri in "Table2".

Ogni "Riga" definita all'interno di una tabella è un set di valori di dati (parametro) che si desidera accettare dalla funzione di test. Le righe 9, 14 e 19 definiscono 3 set di dati accettati dalla funzione FirstTable. Analogamente, le righe 26, 30 e 34 definiscono i set di dati per SecondTable.

Si notino le righe 9, 14, 19, 26, 30 e 34 nell'esempio precedente. È possibile definire i metadati specifici della riga. È ora possibile modificare le informazioni sui metadati con i set di dati per la stessa funzione. La priorità per il primo set di dati (riga 9) è 1, la priorità per il secondo set di dati (riga 14) è 2 e il terzo set di dati (riga 19) viene impostato per impostazione predefinita sulla priorità della funzione. Tutte le righe ereditano i metadati dalla funzione a cui è associata la tabella. Se gli stessi metadati vengono specificati di nuovo a livello di riga, eseguirà l'override dei valori dei metadati definiti a livello di funzione.

NOTA: la definizione dello schema di file XML è la stessa per il codice nativo e il codice gestito, ad eccezione delle definizioni dei tipi supportate. Vedere la parte iniziale della sezione "Managed Data Driven Test" di seguito per un altro esempio di come definire i dati. Continuare con il test nativo basato sui dati per comprendere i tipi consentiti nel codice nativo.

Test basato sui dati nativi

Con i set di dati definiti e pronti per l'utilizzo, è ora necessario un modo per qualificare la funzione di test come test basato sui dati e associarla alla tabella che definisce il set di dati. Questa operazione viene eseguita tramite metadati aggiuntivi durante la creazione del 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 */

Per associare la tabella XML al test, aggiungere i metadati "DataSource" al metodo del test. Tramite questa associazione TAEF userà l'origine dati specificata per eseguire il test. Il valore DataSource include tre parti al suo interno:

  1. 'Table:': identifica l'origine dati come tabella XML.
  2. 'DataDrivenTests.xml': si tratta del file che contiene la tabella XML.
  3. '#Table2': dopo il delimeter '#', il valore 'Table2' identifica la tabella specifica all'interno del documento XML da usare. Una singola origine dati tabella XML può contenere più tabelle. TAEF esaminerà il file XML per un elemento Table con un attributo 'Id' che corrisponde al valore specificato.

Nell'esempio precedente è possibile osservare che "SecondTable" è definito prima di "FirstTable". Ciò significa che la funzione "SecondTable" verrà eseguita prima della funzione "FirstTable", ma è stata definita "Table1", la tabella corrispondente a "FirstTable", prima di "Table2", la tabella corrispondente a "SecondTable". Ciò significa sottolineare che l'ordine della definizione di tabella è irrilevante durante l'individuazione e l'esecuzione dei test basati sui dati.

Con il mapping dell'origine dati al metodo di test completato, è ora possibile modificare l'esempio per ottenere i dati dall'origine. Prima di eseguire questa operazione, esaminare il file di intestazione pubblicato, TestData.h. La parte di interesse è:

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 riga 5 mostra l'API da chiamare per recuperare i dati nella funzione. Esaminare i tipi di parametro disponibili per il recupero.

Ok: tutto impostato per riscrivare l'esempio:

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

Le righe 7 e 18 sono le parti principali che sono state modificate per rendere basati sui dati di test. Non è un gran cambiamento. Esaminare l'esecuzione di test basati sui dati per comprendere come sfruttare al meglio TAEF durante l'esecuzione di test basati sui dati.

Test gestito basato sui dati

Si consideri un esempio in cui si desidera stampare le coordinate di un rettangolo nella console. Iniziare con la definizione di queste coordinate come set di dati in un file 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>

Definire il set di dati nell'ambito di una tabella, in questo caso "FirstTable", definito nella riga 3 precedente. È possibile definire tabelle per diversi metodi di test nello stesso file XML.

Si noti che FirstTable definisce i ParameterTypes in anticipo e chiama "Left" come "Int32". La sezione ParameterTypes è facoltativa. Per impostazione predefinita, se le informazioni sul tipo di parametro non vengono fornite, verranno salvate come string.

Esaminare l'elenco dei tipi di parametro supportati.

Se viene specificato un altro tipo di dati, il test genererà un avviso e considererà string.

NOTA: le stringhe di tipo non fanno distinzione tra maiuscole e minuscole, ma devono essere digitate esattamente come illustrato in precedenza.

Ogni "Riga" definita all'interno di una tabella è un set di valori di dati (parametro) che si desidera accettare dalla funzione di test. Le righe 10, 16 e 22 definiscono 3 set di dati che la funzione.

Si notino le righe 10, 16 e 22 nell'esempio precedente. È possibile definire metadati specifici per Row. È ora possibile modificare le informazioni sui metadati con i set di dati per la stessa funzione. La priorità per il primo set di dati (riga 10) è 1, la priorità per il secondo set di dati (riga 16) è 2 e il terzo set di dati (riga 22) viene impostato per impostazione predefinita sulla priorità della funzione. Tutte le righe ereditano i metadati dalla funzione a cui è associata la tabella. Se gli stessi metadati vengono specificati di nuovo a livello di riga, eseguirà l'override dei valori dei metadati definiti a livello di funzione.

NOTA: la definizione dello schema di file XML è la stessa per il codice nativo e il codice gestito, ad eccezione delle definizioni dei tipi supportate. Esaminare la sezione "Definizione dei dati" nella parte superiore di questa pagina per un altro esempio di come definire questa pagina.

A questo momento, sono stati definiti tutti i dati. Nell'esempio seguente viene illustrato come accedervi.

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'associazione della tabella XML a un determinato metodo di test nel codice gestito è molto simile al codice nativo; applica semplicemente i metadati 'DataSource'. Come in precedenza, è costituito da tre parti:

  1. 'Table:': per identificare l'origine dati come tabella XML.
  2. 'CSharpDataDrivenTests.xml': file contenente la tabella XML.
  3. '#FirstTable': dopo il delimeter '#', il valore 'FirstTable' identifica la tabella specifica all'interno del documento XML da usare. TAEF esaminerà il file XML per un elemento Table con un attributo 'Id' che corrisponde al valore specificato.

Si noti che la funzione Second non è basata sui dati. È possibile scegliere di avere solo alcuni dei test per essere guidati dai dati. È anche possibile avere a disposizione ogni test la relativa tabella definita in un file XML diverso.

Nella riga 36 si definisce una proprietà TestContext privata, ad esempio VSTS consiglia la classe TestContext. Si definiscono anche i valutatori pubblici per questa proprietà (righe da 30 a 34). Internamente TAEF carica la proprietà del dizionario di TestContext con il set di dati corrispondente in stato attivo.

TestContext è definito in Microsoft.VisualStudio.TestTools.UnitTesting. Vedere la riga 3 nell'esempio precedente. Dovrebbe essere già incluso come riferimento nella creazione di test gestiti. Non sono quindi necessari riferimenti aggiuntivi per la creazione di test basati sui dati.

Nella riga 18 dell'esempio precedente viene illustrato come recuperare i dati nella funzione. Si noti che i dati sono disponibili in m_testContext.DataRow.

Nome anziché indice per identificare un datarow

TAEF consente di avere una proprietà 'Name' più significativa anziché l'indice per identificare qualsiasi DataRow nell'origine dati. A tale scopo, è sufficiente aggiungere metadati "Name" a livello di riga nell'origine dati. Il primo esempio in questa pagina può essere modificato per usare questa funzionalità come indicato di seguito:

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>

Nell'esempio modificato precedente, 'BlueTransparent' corrisponde all'indice 0. La riga con indice 1 non ha un nome speciale e la riga con indice 2 ha il nome 'BlackTransparent a esso associato. È comunque possibile usare una query di selezione per cercare l'indice 0 o 2 in 'Table1', che troverà la riga corretta. Tuttavia, quando si esegue o si elenca la dll, invece di visualizzare:

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

si vedrà invece:

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

per l'attributo Rows in cui viene fornito l'attributo "Name" a livello di riga. Se la proprietà "Name" non viene specificata per nessuna riga, ad esempio nel caso dell'indice 1 precedente, per impostazione predefinita avrà #<index> in corrispondenza del nome completo del metodo.

SI NOTI che per fornire un attributo "Name" a livello di riga, si sta essenzialmente modificando il modo in cui TAEF interpreta il nome dell'istanza del metodo chiamata con i dati Row corrispondenti.

DataSource come parametro di runtime

TAEF supporta la fornitura dell'origine dati come parametro di runtime. La sintassi per questa operazione è la seguente:

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

Durante la creazione del test in questione, è necessario specificare il nome> di runtime "p:<DataSource" come origine dati. Tenere presente che è necessario specificare la stringa completa, ovvero il nome del file XML e l'ID tabella insieme, in fase di esecuzione. L'elemento TableId non deve essere fornito come metadati di test se l'origine dati viene fornita in fase di esecuzione. Il prefisso "Table:" specifica che si sta cercando un'origine dati della tabella.

È possibile provare questa operazione con uno degli esempi disponibili nella condivisione di versione:

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

DataSource come risorsa

TAEF consente di aggiungere DataSource come risorsa del modulo di test, purché sia conforme alle condizioni seguenti:

In caso di moduli di test nativi, è possibile farlo specificando DataSource come ID risorsa o nome della risorsa. Ecco un esempio di codice:

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

"MyResourceName" è il nome della risorsa definito nel file ResourceDataSource.rc in questo caso:

MyResourceName DATASOURCE_XML "ResourceDataSource.xml"

Nel caso dei moduli di test gestiti, la risorsa può essere specificata solo in un determinato modo, come illustrato nel frammento di file di origine illustrato di seguito:

LANGUAGE_NEUTRAL_MANAGED_RESOURCES = CSharpAdvancedDataDrivenTests.xml

La specifica dei metadati DataSource rimarrà invariata in caso di specificare il file XML DataSource. Analogamente al caso nel codice gestito, è possibile impostare il nome della risorsa come il nome del file XML. È quindi importante comprendere che TAEF cercherà prima di tutto la presenza del file effettivo con il nome DataSource. Se tale file XML non viene trovato, procederà solo con la ricerca della risorsa di test nel modulo di test con il nome o l'ID della risorsa specificato. Poiché l'impostazione di DataSource come risorsa richiede la ricompilazione, è possibile sfruttare questa progettazione copiando il file XML di DataSource nella stessa posizione della DLL di test durante lo sviluppo e assegnando un nome alla risorsa come nome di file XML. Al termine del test, copiare nuovamente il codice XML nella directory del codice e ricompilare come risorsa. Non dimenticare di eliminare il file XML dalla directory di esecuzione. :)

Procedure dettagliate di esempio

Per comprendere vari aspetti dei test basati sui dati basati su tabelle, leggere altre procedure dettagliate di esempio: