Como fazer testes funcionais (que realmente funcionem)

A ideia de fazer este post surgiu porque algumas semanas atrás precisei escrever e realizar casos de teste para o projeto em que estou trabalhando no momento, o CovidApp UFSC.

Queríamos verificar em que ponto estávamos a nível das funcionalidades, saber o que estava rodando corretamente e o que ainda precisava de mais atenção.

Inicialmente, eu e a minha colega fizemos uma primeira versão beeem rudimentar do que viria a ser o documento com os Casos de Teste (que daqui pra frente vou chamar carinhosamente de “CTs”) do app.

Cada CT tinha o seu número, uma espécie de título descrevendo o que queríamos que acontecesse e alguns “subcasos”. O resultado foi algo assim:

1. Uso do app pela primeira vez com sucesso
- Android
- iPhone

...

3. Os dispositivos registram contato quando próximos
- iPhone e Android a < 40cm ⇒ é registrado um contato
- Android e Android a < 40cm ⇒ é registrado um contato
- iPhone e iPhone a < 40cm ⇒ não se reconhecem
- iPhone, iPhone e Android a < 40cm ⇒ é registrado um contato

...

Foi aí que um dos professores que nos orientam recomendou um ótimo artigo com dicas para a escrita de casos de teste, da Daniele Endler. Inclusive recomendo que leia se tiver interesse (mas só depois de terminar esse post aqui, hein! 😜).

Esse primeiro rascunho que acabamos de ver acerta em alguns aspectos, como por exemplo designar um número e um título que identifique cada CT. Mas ele tem sérias limitações, que pudemos perceber e corrigir depois de aplicar as dicas do artigo, e nós vamos ver o porquê. É agora que o negócio fica interessante. 👀

Primeiro, apesar dos títulos serem descritivos, não há nenhuma informação adicional sobre como testar, o que fazer e em que ordem, como saber se o teste passou ou falhou… Em outras palavras, tá tudo muito vago e aberto a diferentes execuções (que podem ou não ser como desejado).

Nessa hora, algo que pode ajudar bastante é observar a própria definição de um Caso de Teste:

“Caso de Teste: conjunto de valores de entrada, pré-condições de execução, resultados esperados e pós-condições de execução, desenvolvidas para um determinado objetivo ou condição de teste.” (IEEE 610)

O que forma um Caso de Teste

Que tal dividir essa informação em pedaços menores?

Conjunto de valores de entrada

Praticamente qualquer software pode ser reduzido a três partes:

1) ele vai receber algum tipo de “entrada” de dados (input)

2) processar as informações com um determinado propósito

3) e liberar uma saída (output) como resultado deste processamento.

Trazendo isso pros CTs, precisamos nos perguntar qual será esse input.

  • Que dados vamos fornecer?
  • Como vamos interagir com a interface? (Clicar no botão A, digitar um e-mail na caixa B)
  • De modo geral, quais ações vamos realizar?

Note que nada disso estava especificado no rascunho, então provavelmente diferentes pessoas utilizariam caminhos diferentes ao testar.

Pré-condições de execução

Pense em algum experimento científico. Pode ser o prisma de luz de Isaac Newton.

Gravura de Isaac Newton com o prisma de luz

Se você reproduzir as mesmas condições, chegará nos mesmos resultados que ele chegou há centenas de anos. Mas o que acontece se você tentar fazer esse experimento de noite? Ou com um cilindro ao invés de um prisma? Pois então.

Analogamente, os nossos Casos de Teste precisam especificar seus pré-requisitos para execução.

  • O app precisa estar rodando num dispositivo iOS?
  • O Wi-fi precisa estar ligado?
  • É necessário entrar com alguma credencial?

Esses são apenas alguns exemplos. A ideia é informar qualquer pessoa que venha a fazer o Caso de Teste o que ela precisa fazer antes mesmo de começar o teste, para que ele seja válido.

Foi algo que adicionamos, então, ao documento.

Resultados esperados

No nosso CT 3, por exemplo, era esperado que “os dispositivos registrassem contato quando próximos” como o próprio título sugere. Mas como isso acontece e como pode ser visualizado/avaliado?

E mais! Qual é o resultado esperado a cada ação realizada no teste?

Já, já, essa ideia vai ficar mais clara.

Pós-condições de execução

Lembra que antes de começar o teste tivemos que preparar o ambiente adequadamente? Da mesma forma, podem ser necessárias algumas ações para “limpar o ambiente” após o teste, permitindo então a execução dos próximos. Essas ações são as pós-condições de execução.

Juntando tudo

Esses conceitos são muito legais, mas a mágica acontece mesmo quando juntamos e usamos tudo isso para formar a estrutura de cada CT. Dá uma olhada no resultado final de um deles:

Captura de tela de um CT

Por “resultado final” entenda “a nova versão do CT em comparação com aquele rascunho inicial”, porque sempre há espaço para melhorias.

Além de seguir a estrutura proposta, tem alguns detalhes importantes que valem ser destacados:

  • O passo-a-passo é uma lista finita (e quanto menor, menos chance de erro humano) em que cada ação tem um resultado esperado correspondente, sem pontas soltas;
  • As ações são curtas e concisas, com verbos no infinitivo ou imperativo (“clicar” ou “clique”, por exemplo) para instruir o(a) tester;
  • O CT é autossuficiente, isto é, qualquer pessoa que tiver ele em mãos é capaz de reproduzir o teste funcional corretamente e avaliar objetivamente se chegou no(s) resultado(s) esperado(s).

Escrever os CTs desta maneira permite uma clareza maior dos objetivos dos testes. E a grande vantagem dessa metodologia pra mim é que ela também permite estabelecer um padrão e documentar as informações de modo que sejam reutilizáveis e acessíveis.

E você? Como gosta de fazer os seus testes?