O que são testes automatizados?
Nesta unidade, você aprenderá sobre os benefícios dos testes automatizados e os tipos de testes que você pode realizar. Você também aprenderá o que faz um bom teste e será apresentado a algumas das ferramentas de teste que estão disponíveis para você.
O que são testes automatizados?
Os testes automatizados utilizam software para executar o código e comparar os resultados reais com os resultados esperados. Compare isto com os testes exploratórios ou manuais, em que um humano segue, normalmente, instruções num plano de teste para verificar se o software funciona conforme o esperado.
Os testes manuais têm as suas vantagens. No entanto, à medida que a base do código aumenta de tamanho, testar todas as funcionalidades manualmente (incluindo casos periféricos) pode tornar-se repetitivo, entediante e propenso a erros. Os testes automatizados podem ajudar a eliminar parte dessa carga e permitir que os testadores manuais se concentrem no que fazem melhor: garantir que seus usuários tenham uma experiência positiva com seu software.
A pirâmide de testes
Quando pensamos em testes automatizados, é comum separar os testes em camadas. Mike Cohn propõe este conceito, conhecido como a pirâmide de testes, no seu livro Succeeding with Agile.
Embora esta seja uma versão simplista do modelo de Cohn, o conceito ilustra que você concentra a maior parte de seu esforço em escrever testes que verificam os níveis fundamentais do seu software (texto explicativo 1 na pirâmide), como funções, classes e métodos. Você concentra progressivamente menos esforço à medida que os recursos são combinados, como na camada de interface do usuário (UI) (texto explicativo 2 na pirâmide). A ideia é que, se você puder verificar se cada componente de nível inferior funciona como esperado isoladamente, os testes nos níveis mais altos precisarão apenas verificar se vários componentes trabalham juntos para obter o resultado esperado.
Quando é que devo escrever testes?
A resposta depende principalmente das suas necessidades e da experiência na escrita de testes.
Nunca é demasiado tarde para começar a adicionar testes para código que já tenha escrito e implementado. Este facto aplica-se especialmente nos casos das funcionalidades que, muitas vezes, deixam de funcionar corretamente ou exigem a maioria dos esforços por parte da sua equipa de testes.
Quando você relaciona testes com integração contínua e pipelines de entrega contínua, dois conceitos sobre os quais você ouvirá falar são teste contínuo e deslocamento para a esquerda.
Testes contínuos significam que os testes são executados no início do processo de desenvolvimento, à medida que cada alteração passa pelo pipeline. “Shift left” significa considerar a qualidade do software e os testes numa fase mais precoce do processo de desenvolvimento.
Por exemplo, os desenvolvedores geralmente adicionam casos de teste à medida que desenvolvem seu recurso e executam todo o conjunto de testes antes de enviar a alteração para o pipeline. Essa abordagem ajuda a garantir que o recurso que eles estão criando se comporte conforme o esperado e que não interrompa os recursos existentes.
Aqui está um pequeno vídeo onde Abel Wang, Cloud Advocate da Microsoft, explica como garantir que você mantenha a qualidade em seu plano de DevOps.
Pergunte ao Abel
Mudar para a esquerda geralmente exige que os testadores se envolvam no processo de design, mesmo antes de qualquer código para o recurso ser escrito. Compare isso com o modelo "handoff", onde a equipe de teste é apresentada com novos recursos para testar somente depois que o software é projetado e escrito. Um bug descoberto no final do processo pode afetar o cronograma de entrega da equipe, e bugs podem ser descobertos semanas ou até meses depois que o desenvolvedor criou originalmente o recurso.
A desvantagem
Com os testes automatizados, há uma compensação. Embora o teste automatizado permita que os testadores concentrem seu tempo verificando a experiência do usuário final, os desenvolvedores podem precisar dedicar mais tempo para escrever e manter seu código de teste.
No entanto, o objetivo do teste automatizado é ajudar a garantir que os testadores recebam apenas o código da mais alta qualidade, código que comprovadamente funciona conforme o esperado. Portanto, os desenvolvedores podem recuperar parte do seu tempo tendo que lidar com menos bugs ou evitando regravações de código por causa de um caso de borda que eles não tinham considerado originalmente.
Vantagens adicionais
A documentação e a capacidade de refatorar seu código mais facilmente são dois benefícios adicionais do teste automatizado.
Documentação
Os planos de testes manuais podem servir como um tipo de documentação sobre como o software se deve comportar e por que motivo existem determinadas funcionalidades.
Os testes automatizados podem servir o mesmo objetivo. O código de teste automatizado utiliza frequentemente um formato legível por humanos. O conjunto de entradas que você fornece representa os valores que seus usuários podem inserir. Cada saída associada especifica o resultado que seus usuários devem esperar.
Na verdade, muitos desenvolvedores seguem o método de desenvolvimento orientado a teste (TDD) escrevendo seu código de teste antes de implementar um novo recurso. A ideia é escrever um conjunto de testes, muitas vezes chamados specs, que inicialmente falham. Em seguida, o programador escreve código incrementalmente para implementar a funcionalidade até passarem todos os testes. Não só os specs documentam os requisitos, mas o processo TDD também ajuda a garantir que apenas a quantidade necessária de código foi escrita para implementar a funcionalidade.
Refatorização
Suponhamos que tem uma base de código grande que queira refatorizar para confirmar que determinadas partes são executadas mais rapidamente. Como poderá saber se os seus esforços de refatorização não farão com que partes da sua aplicação deixem de funcionar corretamente?
Os testes automatizados servem como um tipo de contrato. Ou seja, você especifica as entradas e os resultados esperados. Quando tem um conjunto de testes aprovados, tem uma maior capacidade de experimentar e refatorizar o código. Quando fizer uma alteração, tem apenas de executar os seus testes e confirmar que continuam a ser bem sucedidos. Depois de atingir suas metas de refatoração, você pode enviar sua alteração para o pipeline de construção para que todos possam se beneficiar, mas com um risco menor de algo quebrar.
Que tipos de testes automatizados existem?
Existem muitos tipos de testes automatizados. Cada teste serve um propósito distinto. Por exemplo, pode executar testes de segurança para ajudar a verificar que apenas os utilizadores autorizados podem aceder a uma parte do software ou a uma das suas funcionalidades.
Quando mencionamos a integração contínua e o pipeline de construção, normalmente estamos nos referindo a testes de desenvolvimento. Os testes de programação referem-se a testes que pode executar antes de implementar a aplicação num teste ou num ambiente de produção.
Por exemplo, o teste de fiapos, uma forma de análise de código estático, verifica seu código-fonte para determinar se ele está em conformidade com o guia de estilo da sua equipe. O código formatado de forma consistente é mais fácil de ler e manter por todos.
Neste módulo, você trabalhará com testes de unidade e testes de cobertura de código.
Os testes de unidades verificam os componentes mais fundamentais do seu programa ou biblioteca, como um método ou função individual. Especifique uma ou mais entradas, juntamente com os resultados esperados. O corredor de teste realiza cada teste e verifica se os resultados reais e esperados correspondem.
Como exemplo, digamos que você tenha uma função que executa uma operação aritmética que inclui divisão. Você pode especificar alguns valores que espera que os usuários insiram junto com valores de caso de borda, como 0 e -1. Se uma determinada entrada produzir um erro ou exceção, você pode verificar se a função produz o mesmo erro.
O teste de cobertura de código calcula a porcentagem do código coberta pelos testes de unidade. O teste de cobertura de código pode incluir ramificações condicionais em seu código para garantir que uma função seja coberta.
Quanto maior a percentagem de cobertura do código, mais confiante pode estar de que mais tarde não irá descobrir um erro no código que não foi totalmente testado. Você não precisa atingir 100% de cobertura de código. Na verdade, quando você começa, você provavelmente descobrirá que tem uma porcentagem baixa, mas isso lhe dá um ponto de partida a partir do qual você pode adicionar testes adicionais que cobrem código problemático ou usado com freqüência.
Manter os testes de unidades isolados
Ao aprender sobre testes de unidade, você pode ouvir termos como simulações, stubs e injeção de dependência.
Lembre-se de que um teste de unidade deve verificar uma função ou método individual, e não como vários componentes interagem. Mas se você tem uma função que chama um banco de dados ou servidor web, como você lida com isso?
Uma chamada para um serviço externo não só quebra o isolamento, como também pode tornar as coisas mais lentas. Se o banco de dados ou o servidor Web ficar inativo ou indisponível, a chamada também poderá interromper a execução do teste.
Usando técnicas como simulação e injeção de dependência, você pode criar componentes que imitam essa funcionalidade externa. Você obterá um exemplo mais adiante neste módulo.
Mais tarde, pode executar testes de integração para verificar se a sua aplicação funciona corretamente com um servidor de base de dados ou Web real.
O que torna um teste bom?
Você será mais capaz de identificar um bom teste à medida que ganhar experiência escrevendo seus próprios testes e lendo testes escritos por outros. Aqui estão algumas diretrizes para começar:
- Não teste por causa de testes: seus testes devem servir a um propósito além de ser um item de lista de verificação a ser riscado. Escreva testes que verifiquem se o código crítico funciona como pretendido e não interrompe a funcionalidade existente.
- Mantenha seus testes curtos: os testes devem terminar o mais rápido possível, especialmente aqueles que acontecem durante as fases de desenvolvimento e construção. Quando os testes são executados à medida que cada alteração se move pelo pipeline, você não quer que eles sejam o gargalo.
- Certifique-se de que seus testes sejam repetíveis: as execuções de teste devem produzir os mesmos resultados todas as vezes, quer você as execute no computador, no computador de um colega de trabalho ou no pipeline de compilação.
- Mantenha seus testes focados: um equívoco comum é que os testes devem cobrir códigos escritos por outras pessoas. Normalmente, seus testes devem abranger apenas seu código. Por exemplo, se estiver a utilizar uma biblioteca de grafos open-source no seu projeto, não precisará de testar essa biblioteca.
- Escolha a granularidade certa: por exemplo, se você estiver executando testes de unidade, um teste individual não deve combinar ou testar várias funções ou métodos. Teste cada função em separado e, mais tarde, escreva testes de integração que verifiquem se vários componentes interagem corretamente.
Que tipos de ferramentas de teste estão disponíveis?
As ferramentas de teste que você usa dependem do tipo de aplicativo que você está criando e do tipo de teste que você deseja executar. Por exemplo, você pode usar o Selenium para executar testes de interface do usuário em muitos tipos de navegadores da Web e sistemas operacionais.
Não importa em que idioma seu aplicativo está escrito, muitas ferramentas de teste estão disponíveis para você usar.
Por exemplo, para aplicações Java, pode escolher Checkstyle para realizar testes lint e JUnit para executar testes de unidades.
Neste módulo, usaremos o NUnit para testes de unidade porque ele é popular na comunidade .NET.