Data-Driven Testing (DDT) e o reaproveitamento dos testes automatizados

Saymon C. A. Oliveira
10 min readSep 15, 2020

--

Qual analista de testes nunca se deparou com a situação onde teve que executar um determinado cenário de teste automatizado várias vezes com o mesmo fluxo funcional onde a única diferença entre os testes eram os dados de entrada ou de saída? 🤯

Bom, para evitar a repetição dos scripts de testes automatizados onde se alteram somente os dados de testes, podemos utilizar a estratégia de Testes Dirigidos a Dados ou conhecida também por Data-Driven Testing (DDT).

Cenário Casas Mineiro 👩‍🏫

Para exemplificar sobre DDT, vamos utilizar o cenário do e-commerce Casas Mineiro:

Créditos ao ilustrador e arquiteto de testes Aldrich Khalled

O e-commerce da Casas Mineiro tem a funcionalidade de marketplace, ou seja, ele permite pesquisar CEPs no site serão retornadas lojas próximas e também os produtos destas lojas próximas referentes ao CEP informado.

Eu como um analista de testes tenho a tarefa de criar scripts de testes automatizados no sistema da Casas Mineiro para a funcionalidade de pesquisa por CEP, tais testes serão:

  • Cenário 1: Pesquisar CEP com lojas próximas
  • Cenário 2: Pesquisar CEP sem lojas próximas

Para cada cenário apresentado anteriormente, teremos um resultado específico:

  • ⚠️ Para o Cenário 1, informaremos CEPs que possuem lojas próximas para validarmos que uma lista de lojas próximas foi apresentada.
  • ⚠️ Já para o Cenário 2, informaremos CEPs que não possuem lojas próximas para validarmos que a mensagem nos informará a ausência de lojas.

Em ambos os cenários, após a implementação, queremos executar nossos scripts de testes automatizados mais de uma vez para testarmos entradas válidas para cada cenário, repetindo então o mesmo cenário várias vezes alterando somente o dado de entrada (CEP). Com o uso da estratégia de DDT, iremos evitar a repetição de código e teremos uma fonte de dados para cada cenário. 🤙🏽

Afinal o que é Data-Driven Testing (DDT)?

Data-Driven Testing é uma metodologia de teste de software onde armazenamos os dados de entrada e de saída de teste em fonte de dados (arquivos). Isto permite que um simples script de teste seja executado várias vezes para todos os dados de entrada e de saída inseridos nesta fonte, reaproveitando o mesmo teste.

Vale lembrar que DDT pode ser aplicado em testes unitários, testes de interface, testes mobile, testes de API e nos testes manuais. Dependendo sempre de uma análise da aplicabilidade.

As fontes de dados para o DDT mais comuns são arquivos csv, xlsx, json e também podemos utilizar APIs, databases ou dados estáticos.

Alguns dos benefícios:

💡 Executar o mesmo script múltiplas vezes alterando os dados de teste.

💡 Reuso de scripts.

💡 Aumento da cobertura de testes.

💡 Diminuição da manutenção.

❌ O erro comum ❌

Um erro muito comum ao iniciarmos a implementação de DDT é confundir com o uso de laço de repetição nos códigos dos testes automatizados, veja o teste automatizado abaixo:

Mas o que poderia estar errado? 🤔

Bem, muita coisa pra falar a verdade…neste exemplo teremos cinco loops sequenciais acontecendo no mesmo fluxo do código (TesteErroComum), ou seja, temos somente UM TESTE com uma lógica de repetição sendo feita cinco vezes e não CINCO TESTES.

Supondo que no terceiro loop “Nome3” por algum motivo acontece um erro e “quebre” o teste com uma exceção. Os demais loops não serão executados “Nome4” e “Nome5” causando uma inconsistência no teste sendo que os mesmos poderiam estar funcionando. 😵

É uma prática errada onde causamos dependência de testes que teoricamente estão no mesmo “teste”. Então, quando for fazer reuso de scripts de testes automatizados variando somente a massa de dados, não use laços de repetições, vem de DDT! ❤

Data-Driven Testing no código

O processo de construção de uma lógica para obtermos dados de testes de arquivos como fonte de dados e utilizar estes dados como parâmetros precisa se estruturar em basicamente quatro etapas:

💾 Arquivo com dados de teste: definir de onde será provido a massa de dados do teste, se for um arquivo CSV, ele deverá estar populado, se for de uma API, devemos criar uma estrutura que retorne os dados e assim para os demais casos.

🔎 Método para leitura do arquivo: método que fica responsável de obter todas as informações do arquivo com dados de teste, necessitando de um driver ou uma biblioteca em conjunto com uma lógica de repetição. Este método é criado para ser reutilizado em quaisquer teste que necessite desta funcionalidade.

⚙️ Método para transformar cada linha do arquivo em um cenário de teste: autoexplicativo, este método utiliza recursos do orquestrador (no nosso caso NUnit) para designar que cada linha obtida do arquivo se torne um cenário de teste, ou seja, neste momento que um teste se “multiplica”.

🧪 Método de teste: método que receberá os dados dos arquivos e serão utilizados dentro do teste em formato de parâmetros de entrada ou saída (de acordo com sua lógica).

Atenção : algumas vezes o Método para de leitura de arquivo e o Método para transformar cada linha do arquivo em um cenário de teste poderão ser um único método, isto varia de acordo com a forma de reuso criada no projeto, não é uma regra.

Implementando testes automatizados com Data-Driven Testing

Para facilitar o entendimento deste assunto, implementei alguns exemplos em .Net Core 3.1 e NUnit dos mais variados tipos de fonte de dados. Você poderá executar estes exemplos tanto no Visual Studio ou no VSCode.

Caso queira preparar sua plataforma de desenvolvimento no VSCode, clique aqui e veja um passo a passo

O framework que iremos utilizar para as funções de DDT será o NUnit na versão 3, é possível realizar este processo em outras linguagens ou frameworks, basta verificar anteriormente se estes recursos apresentam as funções que você irá demandar.

O NUnit utiliza as anotações/decoradores: [Test], [TestCase], [TestCaseSource], onde colocamos esta anotação em cima de cada função que representa um teste ou N testes de acordo com a lógica de DDT.

Nos exemplos abaixo, vamos utilizar como dados de testes principais: nomes e telefones obtidos de diferentes fontes de dados.

DDT simplificado

Inicialmente vamos abordar a forma mais simples de multiplicar seus cenários de testes automatizados através do decorador [TestCase].

Neste caso não estamos dependendo de nenhuma fonte de dados proveniente de arquivos, os dados de testes estarão diretamente no código.

Perceba que estou enviando dois parâmetros por linha de TestCase:

[TestCase(parâmetro1, parâmetro2)]

Isto representará cada parâmetro respectivo da função de teste:

parâmetro1:string name

parâmetro2: string telephoneNumber

Basta dar um refresh que os cenários de testes estarão multiplicados e serão apresentados no Test Explorer para serem executados:

Pronto! 🥳Agora é só variar a quantidade de dados necessária e executar seus testes! A partir daqui, vou apresentar alguns exemplos de uso de DDT com diferentes fontes de dados. 👍🏻

Aqui tem mais alguns exemplos de Data Driven simplificado.

DDT orientado à arquivos csv

Para a fonte de dados do tipo csv, inicialmente precisaremos de um arquivo com as informações, veja um exemplo:

No nosso código fonte, criei um arquivo DataDrivenHelpers.cs e um método para abrir o arquivo e ler cada linha dele transformando-as em um teste, neste caso criaremos uma lista de testes, exemplo da função:

Agora basta criar uma função de teste que receberá a anotação como fonte de dados este csv, onde estamos utilizando a função “ReturnNameTelephone_CSV” da classe “DataDrivenHelpers.cs” conforme exemplo de teste:

Perceba que nesta função temos dois parâmetros de entrada, string name e string telephoneNumber, elas serão preenchidas com valores da fonte de dados e poderão ser utilizada em qualquer parte desta função de teste. Ao dar um refresh na lista de testes, o teste será “multiplicado” pelas quantidade de dados do arquivo fonte:

Feito isso, você já terá seu teste com fonte de dados em um arquivo CSV feito, basta executá-los.

DDT orientado à tabelas excel (xlsx)

Para a fonte de dados do tipo xlsx (planilhas Microsoft), utilizaremos um arquivo com as informações de testes, veja um exemplo:

Precisaremos utilizar um driver para interagirmos com os arquivos xlsx afim de coletar os dados necessários. Para isto iremos instalar o Microsoft Access Database Engine 2010 Redistributable.

O próximo passo é criar uma função para realizar a leitura do arquivo e retornar a lista de casos de testes (List<TestCaseData>), informando o arquivo e a aba que deseja coletar os dados para o teste automatizado. O funcionamento é semelhante a de um banco de dados, necessitando de string de conexão, abrir conexão e executar o comando de coleta. Exemplo da classe e funções:

Agora basta criar uma função que receberá esta lista de casos de testes e para cada linha encontrada no arquivo, será um cenário de teste para ser executado. Para isso, criamos a função “ReturnNameTelephone_XLSX” da classe DataDrivenHelpers.cs conforme exemplo:

Próxima etapa é termos uma função de teste que receberá a anotação como fonte de dados este xlsx, onde estamos utilizando a função ReturnNameTelephone_XLSX da classe DataDrivenHelpers.cs conforme exemplo de teste:

Perceba que nesta função temos dois parâmetros de entrada, string name e string telephoneNumber, eles serão preenchidos com valores da fonte de dados e poderão ser utilizada em qualquer parte desta função de teste. Ao dar um refresh na lista de testes, o teste será “multiplicado” pelas quantidade de dados do arquivo fonte (exatamente igual o cenário de csv):

DDT orientado à API

Para exemplificar da forma de entrada de dados de testes via API, foi feita uma implementação com o framework RestSharp. Utilizaremos a API Rest reques.in que nos retornará vários conjuntos de nomes /e-mails para nosso teste através da rota https://reqres.in/api/users.

A execução da rota nos provê um conjunto de informações dos usuários cadastrados, clique aqui para ver um exemplo do json de retorno. Abaixo o método implementado para execução desta rota:

Este método retornará toda a estrutura do response com os dados dos usuários, mas para nosso exemplo vamos nos preocupar somente com os conjuntos de nomes (user.first_name) e e-mails (user.email) para nosso teste, estando dentro do array “data”. Sendo assim, o próximo passo foi criar um método para transformar cada conjunto de nome / e-mail em um cenário de teste, veja abaixo:

Agora basta criar uma função de teste que receberá a anotação como fonte de dados esta API, onde estamos utilizando a função “ReturnDataUsingAPI” da classe DataDrivenHelpers.cs conforme exemplo de teste:

Perceba que nesta função temos dois parâmetros de entrada, string name e string email, eles serão preenchidos com valores da fonte de dados e poderão ser utilizados em qualquer parte desta função de teste. Ao dar um refresh na lista de testes, o teste será “multiplicado” pelas quantidade de dados do arquivo fonte (exatamente igual o cenário de csv, xlsx):

DDT orientado à banco de dados

Por último mas tão importante quanto os tipos anteriores, é utilizamos dados de testes através de banco de dados, a implementação é bastante parecida com a proveniente de xlsx.

Um banco de dados MySQL na nuvem foi utilizado para este exemplo através do Remote MySQL. A estrutura de tabela é composta por três colunas:

Caso queira replicar em um banco de dados MySQL com estrutura e a carga de dados, clique aqui para acessar o script.

Após, temos que criar uma classe responsável por conter a string de conexão bem como métodos para abrir a conexão MySQL e executar a query de consulta de dados para obter as informações para o teste. Clique aqui para acessar a classe.

O próximo passo é criar um método que executará nossa query na tabela do banco de dados e tornará a lista de casos de testes a partir de cada linha da tabela ser correspondente a um cenário de teste (TestCaseData). Neste caso, a tabela user tem três colunas (cod_user, name e telephone), sendo importante para nosso teste somente name (coluna 1)e telephone (coluna 2).

Exemplo da tabela do banco de dados MySQL preenchida:

Bom, nosso último passo para utilizar estes dados é criar um método de teste que terá o decorador com o método ReturnDataUsingDataBase da classe DataDrivenHelpers:

Perceba que nesta função temos dois parâmetros de entrada, string name e string email, eles serão preenchidos com valores da fonte de dados e poderão ser utilizados em qualquer parte desta função de teste. Caso a conexão e os dados estejam corretos, ao dar um refresh na lista de testes, o teste será “multiplicado” pelas quantidade de dados do arquivo fonte (exatamente igual o cenário de csv, xlsx, API):

Considerações finais 👩🏻‍💻

O uso de recursos de DDT nos testes automatizados é aplicável quando podemos associar reaproveitamento de código e uma carga de dados de testes com características semelhantes: repetir uma inscrição de vestibular, realizar vários checkouts em e-commerce com diferentes produtos, onboarding em aplicativos…

Reforço que este artigo pode ser replicado em diferentes linguagens e tecnologias, sendo necessário um estudo prévio da viabilidade dos recursos que você deseja.

Todo o código aqui apresentado está disponível no meu Github, clique aqui para acessar.

Se puder, compartilhe com outros profissionais que atuem com qualidade de software e que tenham um cenário parecido com o das Casas Mineiro. 😆😆

Qualquer dúvida estou lá no LinkedIn pra dar uma prosinha, uai. ☕

Obrigado (=

--

--

Saymon C. A. Oliveira

QA Engineer, crossfiteiro, trigêmeo, amante da natureza e dos animais. Costumo passar um bom tempo assistindo documentários que envolva história e seres vivos..