Partilhar via


Fonte de dados da tabela

Por favor, certifique-se de que você está familiarizado com a execução básica do TAEF e sabe como criar testes usando-o, antes de prosseguir com esta seção.

Agora que você tem a automação de teste básica escrita e trabalhando com TAEF, você pode se concentrar em cenários onde o mesmo código de teste pode ser usado para trabalhar em vários conjuntos de dados. Para este efeito, o TAEF fornece uma abordagem "baseada em tabelas" para testes baseados em dados. Vamos dar uma olhada em um exemplo simples para entender como criar um teste orientado por dados.

Considere um exemplo simples não orientado por dados no qual você está imprimindo o tamanho e o tema no console. Neste exercício, você converterá esse teste em um teste orientado por dados.

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

Definição dos dados

Agora, você quer que a função acima funcione para um conjunto de tamanhos e temas. Em outras palavras, você quer valores de dados variantes que nossa função pode consumir. Para fazer isso, defina duas tabelas em um arquivo 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>

Agora você definiu duas tabelas, "Table1" e "Table2". Você pode definir tabelas para vários métodos de teste no mesmo arquivo XML.

Observe que na Tabela 1, você definiu os ParameterTypes antecipadamente e escolheu "Size" para ser um inteiro. A seção ParameterTypes é opcional. Por padrão, se as informações de tipo de parâmetro não forem fornecidas, elas serão salvas como uma cadeia de caracteres. Este é o caso de todos os parâmetros na "Tabela 2".

Cada "Linha" definida dentro de uma tabela é um conjunto de valores de dados (parâmetro) que você gostaria que a função de teste aceitasse. As linhas 9, 14 e 19 definem 3 conjuntos de dados que nossa função FirstTable aceitaria. Da mesma forma, as linhas 26, 30 e 34 definem os conjuntos de dados para SecondTable.

Observe as linhas 9, 14, 19, 26, 30 e 34 no exemplo acima - você pode definir metadados específicos para a Linha. Agora há uma maneira de as informações de metadados serem alteradas com conjuntos de dados para a mesma função. A prioridade para o primeiro conjunto de dados (linha 9) é 1, a prioridade para o segundo conjunto de dados (linha 14) é 2 e o terceiro conjunto de dados (linha 19) assume como padrão a prioridade da função. Todas as linhas herdam os metadados da função à qual a tabela está associada. Se os mesmos metadados forem especificados novamente no nível da linha, eles substituirão os valores de metadados definidos no nível da função.

NOTA: A definição de esquema de ficheiro XML é a mesma para código nativo e gerido, exceto para definições de tipo suportadas. Consulte a parte inicial da seção "Managed Data Driven Test" abaixo para obter outro exemplo de como definir os dados. Continue com o Native Data Driven Test para entender os tipos permitidos no código nativo.

Teste orientado por dados nativos

Com os conjuntos de dados definidos e prontos para consumo, agora você precisa de uma maneira de qualificar a função de teste como um teste controlado por dados e associá-la à tabela que define o conjunto de dados. Isso é feito por meio de metadados extras durante a criação do teste:

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

Para associar a tabela XML ao teste, adicione os metadados 'DataSource' ao método do teste. Através desta associação, a TAEF utilizará a DataSource fornecida para conduzir o teste. O valor DataSource tem três partes:

  1. 'Tabela:' - identifica a fonte de dados como sendo uma tabela XML.
  2. 'DataDrivenTests.xml' - este é o arquivo que contém a tabela XML.
  3. '#Table2' - Após o delímetro '#', o valor 'Table2' identifica a tabela específica dentro do documento XML a ser usado. Uma única fonte de dados XML Table pode conter várias tabelas. O TAEF procurará no arquivo XML um elemento Table com um atributo 'Id' que corresponda ao valor especificado.

Você pode ter observado no exemplo acima que "SecondTable" é definido antes de "FirstTable". Isso significa que a função "SecondTable" será executada antes da função "FirstTable", mas você definiu "Table1", a tabela correspondente a "FirstTable", antes de "Table2", a tabela correspondente a "SecondTable". Isso é para enfatizar que a ordem de definição da tabela é irrelevante durante a descoberta e execução dos testes orientados por dados.

Com o mapeamento de nossa fonte de dados para o método de teste concluído, agora você pode modificar o exemplo para obter os dados da fonte. Antes de fazer isso, dê uma olhada no arquivo de cabeçalho publicado, TestData.h. A parte de 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    };

A linha 5 mostra a API a ser chamada para recuperar os dados na função. Dê uma olhada nos Tipos de parâmetros disponíveis para recuperação.

Ok - tudo pronto para reescrever nosso exemplo:

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

As linhas 7 e 18 são as principais partes que mudaram para tornar os dados de teste orientados. Não é muita mudança. Dê uma olhada em Executando testes orientados por dados para entender como aproveitar ao máximo o TAEF durante a execução de testes orientados por dados.

Teste orientado por dados gerenciados

Considere um exemplo em que você deseja imprimir as coordenadas de um retângulo no console. Comece com a definição dessas coordenadas como o conjunto de dados em um arquivo 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>

Defina o conjunto de dados no âmbito de uma Tabela, neste caso "FirstTable", que é definida na linha 3 acima. Você pode definir tabelas para vários métodos de teste no mesmo arquivo XML.

Observe que FirstTable define os ParameterTypes antecipadamente e designa "Left" como "Int32". A seção ParameterTypes é opcional. Por padrão, se as informações de tipo de parâmetro não forem fornecidas, elas serão salvas como uma String.

Dê uma olhada na lista de tipos de parâmetros suportados.

Se qualquer outro tipo de dados for especificado, o teste lançará um aviso e o considerará como uma String.

NOTA: As cadeias de caracteres de tipo não diferenciam maiúsculas de minúsculas, mas devem ser escritas exatamente como mostrado acima.

Cada "Linha" definida dentro de uma tabela, é um conjunto de valores de dados (parâmetro) que você gostaria que a função de teste aceitasse. As linhas 10, 16 e 22 definem 3 conjuntos de dados que a nossa função utiliza.

Observe as linhas 10, 16 e 22 no exemplo acima - você pode definir metadados específicos para Row. Agora você tem uma maneira de alterar as informações de metadados com conjuntos de dados para a mesma função. A prioridade para o primeiro conjunto de dados (linha 10) é 1, a prioridade para o segundo conjunto de dados (linha 16) é 2 e o terceiro conjunto de dados (linha 22) assume como padrão a prioridade da função. Todas as linhas herdam os metadados da função à qual a tabela está associada. Se os mesmos metadados forem especificados novamente no nível da linha, eles substituirão os valores de metadados definidos no nível da função.

NOTA: A definição de esquema de ficheiro XML é a mesma para código nativo e gerido, exceto para definições de tipo suportadas. Dê uma olhada na seção "Definindo os dados" na parte superior desta página para outro exemplo de como definir isso.

Agora, você tem todos os dados definidos. O exemplo a seguir mostra como acessá-lo.

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 }

Associar a tabela XML a um determinado método de teste em código gerenciado é muito semelhante ao código nativo; basta aplicar os metadados 'DataSource'. Como antes, é composto por três partes:

  1. 'Tabela:' - para identificar a fonte de dados como sendo uma tabela XML.
  2. 'CSharpDataDrivenTests.xml' - o arquivo que contém a tabela XML.
  3. '#FirstTable' - Após o delímetro '#', o valor 'FirstTable' identifica a tabela específica dentro do documento XML a ser usado. O TAEF procurará no arquivo XML um elemento Table com um atributo 'Id' que corresponda ao valor especificado.

Observe que a segunda função não é orientada por dados. Pode optar por que apenas alguns dos seus testes sejam orientados por dados. Você também tem a opção de fazer com que cada teste tenha sua tabela definida em um arquivo XML diferente.

Na Linha 36, você define uma propriedade TestContext privada - como o VSTS recomenda TestContext Class. Você também define avaliadores públicos para este imóvel (linhas 30 a 34). Internamente, o TAEF carrega a propriedade do dicionário de TestContext com o conjunto de dados em foco.

TestContext é definido em Microsoft.VisualStudio.TestTools.UnitTesting. Ver linha 3 no exemplo acima. Você já deve estar incluindo isto como uma referência na elaboração de testes geridos. Portanto, nenhuma referência adicional é necessária para a criação de testes orientados por dados.

Na linha 18 do exemplo acima, você mostra como recuperar dados na função. Observe que os dados estão disponíveis em m_testContext.DataRow.

Nome em vez de índice para identificar uma DataRow

O TAEF permite que você tenha uma propriedade 'Name' mais significativa em vez do Index para identificar qualquer DataRow em seu DataSource. Para fazer isso, basta adicionar os metadados 'Nome' ao nível da linha na sua DataSource. Nosso primeiro exemplo nesta página pode ser modificado para usar esse recurso da seguinte maneira:

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>

No exemplo modificado acima, 'BlueTransparent' corresponde ao índice 0. A Linha com índice 1 não tem nenhum nome especial dado a ela e a Linha com índice 2 tem o Nome 'BlackTransparent associado a ela. Você ainda pode usar uma consulta de seleção para procurar o índice 0 ou 2 na 'Tabela1', e ela encontrará a Linha correta. Mas, ao executar ou listar a dll, em vez de ver:

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

Em vez disso, você verá:

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

para as linhas onde o atributo "Nome" é fornecido no nível da linha. Se a propriedade "Name" não for fornecida para nenhuma Row, como no caso do índice 1 acima, o padrão será ter #<index> no nome qualificado do método.

Observe que, por meio do fornecimento de um atributo "Name" no nível Row, você está essencialmente alterando a maneira como o TAEF interpreta o nome da instância da invocação do método com os dados Row correspondentes.

DataSource como um parâmetro de tempo de execução

O TAEF suporta o fornecimento da fonte de dados como um parâmetro de tempo de execução. A sintaxe para isso é a seguinte:

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

Ao criar o teste em questão, você deve especificar o "p:<DataSource runtime name>" como sua fonte de dados. Lembre-se de que você precisa especificar a cadeia de caracteres completa - o nome do arquivo XML, bem como o id da tabela juntos - em tempo de execução. Não se espera que o TableId seja fornecido como metadados de teste se sua fonte de dados for fornecida em tempo de execução. O prefixo "Table:" especifica que você está procurando uma fonte de dados de tabela.

Você pode experimentar isso com um dos exemplos disponíveis no compartilhamento de lançamento:

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

DataSource como um recurso

O TAEF permite que você adicione sua DataSource como um recurso do seu módulo de teste, desde que esteja em conformidade com o seguinte:

No caso de módulos de teste nativos, você pode fazer isso especificando sua DataSource como a id do recurso ou o nome do recurso. Aqui está um exemplo de código:

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

"MyResourceName" é o nome do recurso conforme definido no arquivo ResourceDataSource.rc neste caso:

MyResourceName DATASOURCE_XML "ResourceDataSource.xml"

No caso de módulos de teste gerenciados, o recurso só pode ser especificado de uma determinada maneira, conforme mostrado no trecho do arquivo de códigos-fonte mostrado abaixo:

LANGUAGE_NEUTRAL_MANAGED_RESOURCES = CSharpAdvancedDataDrivenTests.xml

A especificação de metadados DataSource permanecerá a mesma que no caso de especificar o arquivo XML DataSource. Semelhante ao caso no código gerenciado, você pode tornar o nome do recurso igual ao nome do arquivo XML. Por isso, é importante entender que o TAEF procurará primeiro a presença do arquivo real com o nome DataSource. Se tal arquivo XML não for encontrado, só então ele continuará com a procura de recurso de teste no módulo de teste com o nome ou id do recurso fornecido. Como especificar o DataSource como um recurso requer recompilação, você pode aproveitar esse design copiando o arquivo XML DataSource para o mesmo local que a dll de teste durante o desenvolvimento (e nomeando o nome do recurso para ser o mesmo que o nome do arquivo XML). Depois de concluir o teste, copie o XML de volta para o diretório de código e recompile como um recurso. Não se esqueça de excluir o arquivo XML do diretório de execução! :)

Exemplo de passo a passo

Para compreender vários aspetos do teste orientado por dados baseado em tabela, leia mais alguns exemplos passo a passo: