O que testar e sua abordagem

O que testar, ao contrário do que são testes, é uma pergunta importante para todas as equipes. Os testes são um meio para um fim, e escolher como priorizar o teste de diferentes partes da sua base de código pode ser difícil.

A melhor maneira de priorizar é baseada na sua base de código e nas metas da sua equipe. No entanto, é importante lembrar que, embora leve pouco tempo e largura de banda para criar muitos testes pequenos (na parte inferior da pirâmide de teste, como testes de unidade) que tenham muita cobertura de código, eles não necessariamente reduzem o risco geral para o projeto.

O teste de unidade foi concluído: a
  gaveta é aberta. Falha no teste de integração: a gaveta se aproxima da alça
  de outra gaveta e não pode ser aberta mais vezes.
Exemplo de quando os testes de unidade por conta própria são inúteis.

Para escolher o que testar primeiro, pense nos principais casos de uso do seu aplicativo, site ou biblioteca. Isso pode acontecer ao programar testes de componentes em partes críticas do site, os principais componentes que sustentam a experiência do usuário. Por exemplo, os desenvolvedores de um site que permite aos usuários fazer upload e gerenciar dados de séries temporais devem imaginar e testar as diferentes maneiras como um usuário pode executar essas tarefas.

Outra abordagem de priorização envolve conseguir o máximo de informações. Se você tem uma parte "perigosa", legada ou com carga de carga mal escrita da base de código em que ninguém da sua equipe gosta de trabalhar, pode ser útil criar testes em torno dela para tornar o comportamento mais consistente antes de ignorá-la ou refatorá-la para corrigi-la. Pense nisso como a estrutura de um prédio que já foi condenado, mas ainda abriga seu data center.

Dimensionalidade

Introduzimos o conceito de pirâmide de teste, ou outra forma de teste, mas eles tendem a apresentar apenas uma única dimensão de teste: uma linha que vai de escopo pequeno, testes de unidade simples a testes complexos e abrangentes: testes de unidade, testes de integração versus testes de ponta a ponta.

No entanto, alguns da longa lista de possíveis tipos de teste não representam um nível de complexidade, mas sim metas ou técnicas de teste. Por exemplo, testes preliminares são uma categoria diferente de teste, que pode ser de unidade, completo ou outros, mas têm o objetivo de dar aos testadores a confiança geral de que o projeto que está sendo testado está em um estado válido. Os testes visuais também podem ser úteis em um componente pequeno ou no site como um todo.

Sua base de código terá requisitos exclusivos. Por exemplo, pode ser muito mais importante na base de código se alinhar em um único recurso, programar diferentes tipos de testes para garantir que ele funcione corretamente. Um novo recurso que precisa de testes raramente é um único componente, função ou abordagem, e o impacto dele no projeto pode ser distribuído amplamente e em diferentes escalas.

As prioridades de teste também podem depender das necessidades da sua empresa. Sistemas altamente técnicos podem exigir testes de unidade complexos para confirmar se um algoritmo exclusivo é executado corretamente, enquanto as ferramentas altamente interativas provavelmente se concentrarão em testes visuais ou de ponta a ponta para confirmar se entradas de toque complexas geram a resposta correta.

Sua abordagem aos testes

Tente se concentrar em testar os casos de uso da sua base de código, independente da escala. Imagine como o usuário pode usar qualquer parte do projeto: isso pode representar um único componente, uma função de nível inferior ou um caso de uso de ponta a ponta. Isso também pode revelar deficiências nas abstrações em qualquer escala, se você achar que o teste não pode interagir corretamente com o código em teste.

É importante que cada caso de teste tenha uma meta claramente definida. Grandes testes "pega-tudo" podem ser difíceis de gerenciar, assim como em códigos que não são de teste.

Uma lição sobre o desenvolvimento orientado por testes

O desenvolvimento orientado a testes (TDD, na sigla em inglês) é uma abordagem exclusiva para testes (ortogonal para escalonar ou tipos), porque envolve escrever testes com a intenção de falhar, pelo menos no início. Isso pode se aplicar a testes manuais e automatizados: você descrever as metas que gostaria de alcançar, descobrir o que está faltando na sua solução ou código atual e usar o teste reprovado como orientação para uma solução.

É claro que não é útil testar todos os cenários possíveis em um aplicativo ou componente hipotético, mesmo antes de começar a criá-lo. O TDD tem seu lugar e pode ser útil à medida que sua base de código fica mais complexa.

O TDD também é uma boa prática ao corrigir bugs. Se for possível codificar o caso de reprodução de um bug, ele poderá ser colocado em um teste automatizado que falhará inicialmente. Depois de corrigir o bug, o teste é aprovado, permitindo determinar se a correção foi bem-sucedida sem confirmação manual.

Um fluxograma para o desenvolvimento voltado a testes.
Abordar seu código com o desenvolvimento orientado a testes em mente é uma parte da filosofia de testes
.

Caixa opaca versus transparente

Isso se refere à maneira como você testa qualquer parte do seu sistema. Se ela for opaca, não será possível ver o interior dela, por exemplo, ao usar a interface pública de uma classe, em vez de inspecionar os componentes internos.

A menos que você tenha um motivo específico para não fazer isso, é melhor começar com testes de caixa opacos para projetar testes com base em como seus componentes são usados e não se distrair com o funcionamento dos componentes internos. Se você depende apenas da interface "pública" de um caminho de código (não necessariamente pública para seus usuários, mas talvez para outras partes do código), pode refatorar e melhorar esse código, sabendo que o teste detectará alterações.

Uma maneira de converter o código "clear box" para que seja mais opaco é introduzir elementos configuráveis, como abstrações para as dependências do código ou callbacks para observar o estado, em vez desse estado estar rigidamente acoplado a outros sistemas. Isso torna o código mais desacoplado e permite fornecer versões de "teste". Como alternativa, você pode simular onde seu código interage com outros sistemas.

Recursos