Condividi tramite


Fonte 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 di test di base con TAEF, è possibile concentrarsi sugli scenari in cui è possibile usare lo stesso codice di test per lavorare su diversi set di dati. A questo scopo, TAEF fornisce un approccio basato su tabella 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 visualizzano dimensioni e tema sulla console. In questo esercizio questo test verrà convertito 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

Ora si vuole 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 ora 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 alto 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 che la funzione FirstTable accetterebbe. 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 disponibile un modo per 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 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 su 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 guidato dai 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:

  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". Si tratta di sottolineare che l'ordine di definizione della tabella è irrilevante durante l'individuazione e l'esecuzione dei test basati sui dati.

Con la mappatura della fonte dati al metodo di test completata, è ora possibile adattare l'esempio per ottenere i dati dalla fonte. Prima di eseguire questa operazione, esamina 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 parametri disponibili per il recupero.

Ok - tutto pronto per riscrivere 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 i dati di test centrali. 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.

Osservare 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 parametri supportati.

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

NOTA: le stringhe di tipo non distinguono tra maiuscole e minuscole, ma devono essere scritte 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 per la nostra funzione.

Si notino le righe 10, 16 e 22 nell'esempio precedente. È possibile definire metadati specifici di 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) corrisponde alla 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 definirlo.

Ora 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; è sufficiente applicare i metadati 'DataSource'. Come in precedenza, è costituito da tre parti:

  1. 'Table:': per identificare l'origine dati come tabella XML.
  2. 'CSharpDataDrivenTests.xml' : file che contiene 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 seconda funzione non è basata sui dati. È possibile scegliere di fare in modo che solo alcuni dei test siano basati sui dati. È anche possibile definire la tabella di ogni test in un file XML diverso.

Nella riga 36 si definisce una proprietà TestContext privata, come vsts consiglia la classe TestContext. Si definiscono anche i valutatori pubblici per questa proprietà (linee da 30 a 34). TAEF carica internamente la proprietà del dizionario di TestContext con il set di dati corrispondente in evidenza.

TestContext è definito in Microsoft.VisualStudio.TestTools.UnitTesting. Vedere la riga 3 nell'esempio precedente. Dovresti già includerlo come riferimento nella gestione della creazione dei test. 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 invece di Index per identificare un datarow

TAEF consente di avere una proprietà "Nome" più significativa anziché l'indice per identificare un DataRow nella tua origine dati. A tale scopo, aggiungi semplicemente i metadati "Name" nel tuo DataSource a livello di riga. 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 associato ad essa e la riga con indice 2 ha il nome 'BlackTransparent' associato ad essa. È 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, anziché visualizzare:

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

si vedrà invece:

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

per le righe in cui l'attributo "Name" viene fornito 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 "p:<nome di runtime 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 di una 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 di 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à identica a quella specificata nel 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 ricompilatazione, è possibile sfruttare questa progettazione copiando il file XML di DataSource nello stesso percorso della DLL di test durante lo sviluppo e la denominazione del nome della risorsa come nome file XML. Al termine del test, copiare di nuovo il codice XML nella directory del codice e ricompilare come risorsa. Non dimenticare di eliminare il file XML dalla directory di esecuzione. :)

Esempi di percorsi guidati

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