Diferentes tipos de testes de software

Compare diferentes tipos de testes de software, como teste de unidade, teste de integração, teste funcional, teste de aceitação e muito mais!

Sten Pittet Sten Pittet

Existem muitos tipos diferentes de testes que você pode usar para se certificar de que as alterações no seu código estão funcionando como esperado. Mas nem todos os testes são iguais, e a gente vai ver aqui como as principais práticas de teste diferem umas das outras.

Teste manual vs. automatizado

Em um alto nível, precisamos fazer uma distinção entre testes manuais e automatizados. Teste manual é feito pessoalmente, clicando no aplicativo ou interagindo com o software e as APIs com as ferramentas adequadas. Isso tem um custo muito alto e requer alguém para configurar um ambiente e executar os testes por si mesmo, e pode estar propenso a erros humanos, uma vez que o testador pode cometer erros ortográficos ou omitir etapas no script de teste.

Testes automatizados, por outro lado, são realizados por uma máquina que executa um script de teste escrito com antecedência. Esses testes podem variar muito em termos de complexidade, de verificar um único método em uma classe a garantir que realizar uma sequência de ações complexas na interface do usuário leve aos mesmos resultados. São muito mais robustos e confiáveis que testes automatizados. Porém, a qualidade dos testes automatizados depende da qualidade com que seus scripts de teste foram escritos. Se você está apenas começando a usar testes, pode ler o tutorial de integração contínua para ajudar com seu primeiro pacote de teste. Se quiser conhecer mais ferramentas de teste, consulte os tutoriais de teste de DevOps.

Teste automatizado é um componente essencial de integração contínua e entrega contínua e é uma ótima maneira de dimensionar seu processo de QA conforme você adiciona novos recursos ao seu aplicativo. Porém, ainda há valor em realizar alguns testes manuais com o que se chama de teste exploratório, como veremos neste guia.

Os diferentes tipos de testes

Testes de unidade

Testes de unidade são feitos em um nível muito baixo, próximo ao código-fonte do seu aplicativo. Eles consistem em testar métodos e funções individuais de classes, componentes ou módulos usados pelo seu software. Testes de unidade geralmente têm um baixo custo para automatizar e podem ser executados muito rapidamente por um servidor de integração contínua.

Testes de integração

Testes de integração verificam se diferentes módulos ou serviços usados pelo seu aplicativo funcionam bem juntos. Por exemplo, pode ser testar a interação com o banco de dados ou garantir que os microsserviços funcionem juntos conforme o esperado. A execução desses tipos de testes tem um custo maior, uma vez que exigem que várias partes do aplicativo estejam ativas e em execução.

Testes funcionais

Os testes funcionais têm como foco os requisitos de negócios de uma aplicação. Eles só verificam a saída de uma ação e não verificam os estados intermediários do sistema ao executar essa ação.

Às vezes há uma confusão entre testes de integração e testes funcionais, uma vez que ambos exigem vários componentes para interagirem entre si. A diferença é que um teste de integração pode simplesmente verificar que você pode consultar o banco de dados, enquanto um teste funcional esperaria obter um valor específico do banco de dados conforme definido pelos requisitos do produto.

Testes de ponta a ponta

Teste de ponta a ponta replica o comportamento de um usuário com o software em um ambiente de aplicativo completo. Ele verifica se vários fluxos de usuário funcionam como o esperado e podem ser tão simples quanto carregar uma página da web ou fazer login ou cenários muito mais complexos verificando notificações por e-mail, pagamentos on-line etc.

Testes de ponta a ponta são muito úteis, mas têm um alto custo e podem ser difíceis de atualizar quando automatizados. Recomendamos ter alguns testes de ponta a ponta essenciais e contar mais com tipos de testes de nível inferior (testes de unidade e de integração) para poder identificar rapidamente alterações que causam falha.

Teste de aceitação

Os testes de aceitação são testes formais executados para verificar se um sistema atende aos requisitos de negócios. Eles exigem que todo o aplicativo esteja ativo e em execução e foca em replicar os comportamentos do usuário. Porém, também pode ir mais além e medir o desempenho do sistema e rejeitar alterações se determinadas metas não forem cumpridas.

Teste de desempenho

Os testes de desempenho verificam os comportamentos do sistema quando ele está sob carga significativa. Estes testes não são funcionais e podem ter a forma diferente para entender a confiabilidade, estabilidade e disponibilidade da plataforma. Por exemplo, ele pode estar observando tempos de resposta ao executar um grande número de solicitações, ou ver como o sistema se comporta com um significativo de dados.

Testes de desempenho são, por natureza, bastante caros de implementar e executar, mas podem ajudá-lo a entender se novas alterações forem degradar seu sistema.

Teste de sanidade

Testes de sanidade são testes básicos que verificam a funcionalidade básica do aplicativo. Eles são feitos para terem execução rápida, e sua meta é garantir que os principais recursos do seu sistema estejam funcionando conforme o esperado.

Os testes de sanidade podem ser úteis logo após um novo build ser feito para decidir se você pode ou não executar testes mais caros, ou logo após uma implementação para garantir que o aplicativo esteja sendo executado como deveria no ambiente recém-implementado.

Como automatizar seus testes

Uma pessoa pode executar todos os testes mencionados acima, mas será muito dispendioso e contraproducente fazer isso. Como humanos, temos capacidade limitada para realizar um grande número de ações de maneira repetível e confiável. Porém, uma máquina pode fazer isso de modo rápido e fácil e testará se a combinação de login/senha funciona pela 100ª vez sem reclamar.

Para automatizar seus testes, você primeiro vai precisar escrevê-los de modo programático usando uma estrutura de teste adequada ao seu aplicativo. PHPUnit, Mocha, RSpec são exemplos de estruturas de teste que você pode usar para PHP, Javascript e Ruby, respectivamente. Há muitas opções por aí para cada linguagem, assim, você precisa pesquisar e pedir para as comunidades de desenvolvedores descobrirem qual seria a melhor estrutura para você.

Quando seus testes podem ser executados por meio de script do seu terminal, você pode fazer com que sejam executados automaticamente por um servidor de integração contínua, como o Bamboo, ou usar um serviço de nuvem, como o Bitbucket Pipelines. Essas ferramentas vão monitorar seus repositórios e executar seu pacote de teste sempre que novas alterações forem enviadas ao repositório principal.

Cada push para o repositório é verificado graças ao Bitbucket Pipelines

Se você está apenas começando a usar testes, pode ler o tutorial de integração contínua para ajudar com seu primeiro pacote de teste.

Teste exploratório

Quanto mais recursos e melhorias forem incluídos no seu código, mais você precisará testar para garantir que seu sistema funcione adequadamente. Então, para cada bug que você corrigir, é bom verificar para que não voltem em novas versões. Automação é crucial para tornar isso possível e escrever testes mais cedo ou mais tarde se tornará parte do seu fluxo de desenvolvimento.

Assim, a pergunta é: ainda vale a pena realizar teste manual? A resposta breve é sim, e deve ser focado no que chamamos de teste exploratório, em que a meta é descobrir erros não óbvios.

Uma sessão de testes exploratórios não deve exceder duas horas e precisa ter um escopo claro para ajudar os testadores a se concentrar em uma área específica do software. Uma vez que todos os testadores foram informados, cabe a eles tentar várias ações para verificar como o sistema se comporta. Esse tipo de teste é caro por natureza, mas é bastante útil para descobrir problemas de interface do usuário ou verificar fluxos de trabalho complexos do usuário. É algo que realmente vale a pena fazer sempre que um novo recurso significativo é adicionado ao seu aplicativo para ajudar a entender como ele se comporta em casos de borda.

Uma observação sobre testes

Para terminar este guia, é importante falar sobre o objetivo de testar. Tão importante quanto testar que os usuários podem usar seu aplicativo (posso entrar, posso salvar um objeto), é testar se seu sistema não quebra quando dados ruins ou ações inesperadas são executadas. Você precisa antecipar o que aconteceria quando um usuário faz um erro de digitação, tenta salvar um formulário incompleto ou usa a API errada. Você precisa verificar se alguém pode facilmente comprometer os dados, obter acesso a um recurso que não deveria. Uma boa suíte de testes deve tentar quebrar seu aplicativo e ajudar a entender seu limite.

E, finalmente, os testes são código também! Portanto, não os esqueça durante a revisão de código pois eles podem ser o portão final para a produção.