Fonte de dados da tabela
Verifique se você está familiarizado com a execução básica do TAEF e saiba como criar testes usando-o antes de prosseguir com esta seção.
Agora que você tem automação de teste básica escrita e trabalhando com TAEF, você pode se concentrar em cenários em que o mesmo código de teste pode ser usado para trabalhar em conjuntos variados de dados. Para essa finalidade, o TAEF fornece uma abordagem "baseada em tabela" para testes controlados por dados. Vamos dar uma olhada em um exemplo simples para entender como criar um teste controlado por dados.
Considere um exemplo simples não controlado por dados no qual você está imprimindo o tamanho e o tema no console. Neste exercício, você converterá esse teste em um teste controlado 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 */
Definindo os dados
Agora, você deseja que a função acima funcione para um conjunto de tamanhos e temas. Em outras palavras, você deseja 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, em Table1, 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. Esse é o caso de todos os parâmetros em "Table2".
Cada "Linha" definida em 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 três 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 da Linha. Agora há 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 9) é 1, a prioridade para o segundo conjunto de dados (linha 14) é 2 e o terceiro conjunto de dados (linha 19) usa 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, ele substituirá os valores de metadados definidos no nível da função.
OBSERVAÇÃO: a definição de esquema de arquivo XML é a mesma para código nativo e gerenciado, exceto para definições de tipo com suporte. Veja a parte inicial da seção "Teste Controlado por Dados Gerenciados" abaixo para obter outro exemplo de como definir os dados. Continue com o Teste Controlado por Dados Nativos para entender os tipos permitidos no código nativo.
Teste controlado 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. Por meio dessa associação, o TAEF usará o DataSource especificado para conduzir o teste. O valor do DataSource tem três partes:
- 'Table:' – isso identifica a fonte de dados como sendo uma tabela XML.
- 'DataDrivenTests.xml' – esse é o arquivo que contém a tabela XML.
- '#Table2' – Após o delimeter '#', o valor 'Table2' identifica a tabela específica dentro do documento XML a ser usado. Uma única fonte de dados da Tabela XML pode conter várias tabelas. O TAEF examinará o arquivo XML de um elemento Table com um atributo 'Id' que corresponde 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 da definição de tabela é irrelevante durante a descoberta e execução dos testes controlados 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 origem. 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âmetro disponíveis para recuperação.
Ok - tudo pronto para gravar novamente 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 partes main que foram alteradas para tornar os dados de teste controlados. Não há muita mudança. Dê uma olhada em Executando testes controlados por dados para entender como aproveitar ao máximo o TAEF durante a execução de testes controlados por dados.
Teste controlado por dados gerenciados
Considere um exemplo em que você deseja imprimir as coordenadas de um retângulo no console. Comece definindo essas 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 escopo de uma Tabela, nesse caso , "FirstTable", que é definido 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 chama "Left" para ser um "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 Cadeia de Caracteres.
Dê uma olhada na lista de tipos de parâmetro com suporte.
Se qualquer outro tipo de dados for especificado, o teste lançará um aviso e o considerará um String.
OBSERVAÇÃO: as cadeias de caracteres de tipo não diferenciam maiúsculas de minúsculas, mas devem soletrar 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 três conjuntos de dados que nossa função.
Observe as linhas 10, 16 e 22 no exemplo acima – você pode definir metadados específicos de 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) usa 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, ele substituirá os valores de metadados definidos no nível da função.
OBSERVAÇÃO: a definição de esquema de arquivo XML é a mesma para código nativo e gerenciado, exceto para definições de tipo com suporte. Dê uma olhada na seção "Definindo os dados" na parte superior desta página para obter 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 no código gerenciado é muito semelhante ao código nativo; basta aplicar os metadados 'DataSource'. Como antes, ele é composto por três partes:
- 'Table:' – para identificar a fonte de dados como sendo uma tabela XML.
- 'CSharpDataDrivenTests.xml' – o arquivo que contém a tabela XML.
- '#FirstTable' – após o delimeter '#', o valor 'FirstTable' identifica a tabela específica dentro do documento XML a ser usado. O TAEF examinará o arquivo XML de um elemento Table com um atributo 'Id' que corresponde ao valor especificado.
Observe que a Segunda função não é controlada por dados. Você pode optar por ter apenas alguns de seus testes para serem controlados 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 a Classe TestContext. Você também define assessores públicos para essa propriedade (linhas 30 a 34). Internamente, o TAEF carrega a propriedade de dicionário de TestContext com o conjunto de dados correspondente em foco.
TestContext é definido em Microsoft.VisualStudio.TestTools.UnitTesting. Consulte a linha 3 no exemplo acima. Você já deve incluir isso como uma referência na criação de teste gerenciado. Portanto, nenhuma referência adicional é necessária para criar testes controlados 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 Indexar para identificar um DataRow
O TAEF permite que você tenha uma propriedade 'Name' mais significativa em vez do Índice para identificar qualquer DataRow em seu DataSource. Para fazer isso, basta adicionar metadados 'Name' no nível de linha em seu 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 e a Linha com índice 2 tem o Nome 'BlackTransparent associado a ele. Você ainda pode usar uma consulta de seleção para procurar o índice 0 ou 2 em 'Table1', 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 em que o atributo "Name" é fornecido no nível de linha. Se a propriedade "Name" não for fornecida para nenhuma Linha, como no caso do índice 1 acima, o padrão será ter #<index> no nome qualificado do método.
OBSERVE que, por meio de fornecer um atributo "Name" no nível da linha, você está essencialmente alterando a maneira como o TAEF interpreta o nome da instância da invocação do método com os dados de Linha correspondentes.
DataSource como um parâmetro runtime
O TAEF dá suporte ao fornecimento da fonte de dados como um parâmetro de runtime. 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 "nome> do runtime p:<DataSource" como sua Fonte de Dados. Tenha em mente que você precisa especificar a cadeia de caracteres completa - o nome do arquivo XML, bem como a ID da tabela em conjunto - em runtime. Não se espera que o TableId seja fornecido como metadados de teste se a fonte de dados for fornecida em runtime. 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 versão:
te Examples\CPP.RuntimeDataSource.Example.dll /p:MyDataSource=Table:RuntimeDataSourceExample.xml#SimpleTable
DataSource como um recurso
O TAEF permite que você adicione o DataSource como um recurso do 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 o DataSource como a ID do recurso ou o nome do recurso. Veja 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 snippet de arquivo de origem mostrado abaixo:
LANGUAGE_NEUTRAL_MANAGED_RESOURCES = CSharpAdvancedDataDrivenTests.xml
A especificação de metadados do DataSource permanecerá a mesma que no caso de especificar o arquivo XML do DataSource. Semelhante ao caso no código gerenciado, você pode tornar o nome do recurso o mesmo que o nome do arquivo XML. Portanto, é importante entender que o TAEF primeiro procurará a presença do arquivo real com o nome datasource. Se esse arquivo XML não for encontrado, ele continuará procurando o recurso de teste no módulo de teste com o nome ou a ID do recurso fornecido. Como especificar o DataSource como um recurso requer a compilação novamente, você pode aproveitar esse design copiando o arquivo XML do DataSource para o mesmo local que a dll de teste durante o desenvolvimento (e nomeando o nome do recurso como o mesmo que o nome do arquivo XML). Depois de terminar de testar, copie o XML de volta para o diretório de código e compile novamente como um recurso. Não se esqueça de excluir o arquivo XML do diretório de execução! :)
Exemplos de passo a passo
Para entender vários aspectos dos testes baseados em dados baseados em tabela, leia mais alguns exemplos de passo a passo: