O que é teste automatizado?
Nesta unidade, você aprenderá os benefícios do teste automatizado e os tipos de teste que pode realizar. Você também aprenderá no que consiste um bom teste e conhecerá algumas das ferramentas de teste disponíveis para você.
O que é teste automatizado?
Testes automatizados usam software para executar o código e comparar os resultados reais com os resultados esperados. Compare isso com teste exploratório ou teste manual, em que um ser humano geralmente segue as instruções em um plano de teste para verificar se o software funciona conforme o esperado.
Teste manual tem seus benefícios. Porém, conforme o tamanho da sua base de código aumenta, testar todos os recursos manualmente (inclusive casos extremos) pode se tornar repetitivo, entediante e propenso a erros. O teste automatizado pode ajudar a eliminar parte desse fardo e permitir que testadores manuais se concentrem no que eles sabem fazer melhor: garantir que os usuários tenham uma experiência positiva com seu software.
A pirâmide de teste
Quando pensamos em teste automatizado, é comum separar os testes em camadas. Mike Cohn propõe esse conceito, conhecido como a pirâmide de teste, em seu livro Succeeding with Agile (Obtendo sucesso com Agile).
Embora essa seja uma versão simplista do modelo de Cohn, o conceito ilustra que você concentra a maior parte do seu esforço de escrever testes que verificam os níveis fundamentais do seu software (balão 1 na pirâmide), como funções, classes e métodos. Você foca progressivamente menos esforço à medida que os recursos são combinados, como na camada da interface do usuário (balão 2 na pirâmide). A ideia é que, se você puder verificar se cada componente de nível inferior funciona conforme o esperado em isolamento, testes em níveis mais altos só precisarão verificar que vários componentes funcionam juntos para obter o resultado esperado.
Quando devo escrever testes?
A resposta depende principalmente das suas necessidades e da sua experiência em escrever testes.
Nunca é tarde demais para começar a adicionar testes para código que você já escreveu e implantou. Isso é especialmente verdadeiro para recursos que frequentemente são interrompidos ou exigem mais esforço de sua equipe de teste.
Ao relacionar teste a pipelines de integração contínua e entrega contínua, dois conceitos sobre os quais você ouvirá falar são testes contínuos e deslocamento à esquerda.
O termo Testes contínuos significa que os testes são executados no início do processo de desenvolvimento e conforme cada alteração se move pelo pipeline. Deslocamento à esquerda significa considerar a qualidade do software e testar mais cedo no processo de desenvolvimento.
Por exemplo, os desenvolvedores geralmente adicionam casos de teste conforme desenvolvem seus recursos e executam o pacote completo de testes antes de enviar a alteração para o pipeline. Essa abordagem ajuda a garantir que ambos os recursos que eles estão criando se comportem conforme o esperado e não interrompam os recursos existentes.
Aqui está um breve vídeo em que Abel Wang, consultores de nuvem na Microsoft, explica como garantir que você mantenha a qualidade em seu plano de DevOps.
Pergunte ao Abel
O deslocamento à esquerda costuma exigir que os testadores se envolvam no processo de design, mesmo antes que qualquer código para o recurso seja escrito. Compare isso com o modelo de "entrega", em que a equipe de teste recebe novos recursos para testar somente depois que o software foi criado 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 originalmente criou o recurso.
Os prós e contras
Com o teste automatizado, há prós e contras. Embora o teste automatizado permita que os testadores dediquem tempo à verificação da experiência do usuário final, talvez os desenvolvedores precisem dedicar mais tempo a escrever e manter o 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 ao precisarem lidar com menos bugs ou ao evitar reescrever códigos devido a um caso extremo que eles não haviam considerado originalmente.
Benefícios adicionais
A documentação e a capacidade de refatorar seu código com mais facilidade são dois benefícios adicionais dos testes automatizados.
Documentação
Planos de teste manual podem servir como um tipo de documentação explicando como o software deve se comportar e por que existem determinados recursos.
Testes automatizados podem servir à mesma finalidade. Código de teste automatizado geralmente usa um formato legível por humanos. O conjunto de entradas que você fornece representa valores que seus usuários podem inserir. Cada saída associada especifica o resultado que os usuários devem esperar.
Na verdade, muitos desenvolvedores seguem o método de Desenvolvimento Orientado por Testes (TDD) escrevendo seu código de teste antes de implementar um novo recurso. A ideia é escrever um conjunto de testes, muitas vezes chamado de especificações, que inicialmente falha. Então, o desenvolvedor escreve incrementalmente o código para implementar o recurso até que todos os testes sejam aprovados. As especificações não apenas documentam os requisitos, como o processo de TDD ajuda a garantir que somente a quantidade necessária de código seja escrita para implementar o recurso.
Refatoração
Digamos que você tenha uma base de código grande que queira refatorar para fazer determinadas partes serem executadas mais rapidamente. Como você sabe que seus esforços de refatoração não causarão interrupção a partes de seu aplicativo?
Os testes automatizados servem como um tipo de contrato. Ou seja, você especifica as entradas e os resultados esperados. Quando você tem um conjunto de testes aprovado, é melhor poder experimentar e refatorar seu código. Quando você faz uma alteração, basta executar os testes e verificar se eles continuam sendo aprovados. Depois de atender a seus objetivos de refatoração, você pode enviar a alteração para o pipeline de build para que qualquer pessoa possa se beneficiar, mas com um menor risco de causar alguma interrupção.
Que tipos de testes automatizados existem?
Há muitos tipos de testes automatizados. Cada teste tem uma finalidade separada. Por exemplo, você pode executar testes de segurança para ajudar a verificar que somente usuários autorizados podem acessar uma parte do software ou um de seus recursos.
Quando mencionamos a integração contínua e o pipeline de build, normalmente estamos nos referindo a testes de desenvolvimento. Testes de desenvolvimento referem-se aos testes que você pode executar antes de implantar o aplicativo em um ambiente de teste ou de produção.
Por exemplo, o teste lint, um formulário de análise de código estático, verifica o código-fonte para determinar se está em conformidade com o guia de estilo da sua equipe. Um código formatado de forma consistente facilita a leitura e manutenção de todos.
Neste módulo, você vai trabalhar com testes de unidade e teste de cobertura de código.
Teste de unidade verifica os componentes mais importantes do seu programa ou biblioteca, como um método ou função individual. Você especifica uma ou mais entradas, juntamente com os resultados esperados. O executor de teste executa cada teste e verifica se os resultados esperados e reais são iguais.
Por exemplo, digamos que você tenha uma função que executa uma operação aritmética que inclui divisão. Você pode especificar alguns valores esperados para os usuários inserirem, juntamente com os valores de caso extremo, como 0 e -1. Se uma dada entrada produzir um erro ou exceção, você poderá verificar se a função produz o mesmo erro.
O teste de cobertura de código calcula o percentual de seu código que é coberto por 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 o percentual de cobertura de código, mais confiança você poderá ter de que não descobrirá depois um bug no código que não tenha sido totalmente testado. Você não precisa alcançar 100% de cobertura de código. Na verdade, quando você começa, é provável que encontre uma porcentagem baixa. No entanto, isso lhe dá um ponto de partida a partir do qual você pode adicionar testes extras que cobrem um código problemático ou usado com frequência.
Manter os testes de unidade isolados
Quando você está aprendendo sobre testes de unidade, 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. Porém, se você tiver 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 apenas quebra o isolamento, mas pode deixar as coisas mais lentas. Se o servidor Web ou banco de dados ficar inativo ou não disponível, a chamada também poderá interromper a execução de teste.
Ao usar técnicas como simulação e injeção de dependência, é possível criar componentes que simulam essa funcionalidade externa. Você verá um exemplo mais adiante neste módulo.
Posteriormente, você pode executar testes de integração para verificar se seu aplicativo funciona corretamente com um servidor Web ou banco de dados real.
O que torna um teste bom?
Você poderá identificar melhor um teste bom conforme você ganha experiência ao escrever seus testes e ler os testes escritos por outras pessoas. Aqui estão algumas diretrizes para começar:
- Não teste só por testar: seus testes devem atender a uma finalidade que não simplesmente riscar um item da lista de verificação. Escreva testes que verifiquem se o código crítico funciona conforme o esperado e não interrompe a funcionalidade existente.
- Mantenha a brevidade dos testes: os testes devem ser concluídos assim que possível, especialmente aqueles que ocorrem durante o desenvolvimento e nas fases de build. Quando os testes são executados conforme cada alteração avança pelo pipeline, você não deseja que eles sejam o gargalo.
- Garanta que os testes sejam repetíveis: as execuções de teste devem produzir os mesmos resultados sempre, não importa se você as executa em seu computador, no computador de um colega de trabalho ou no pipeline de build.
- Mantenha os testes focados: um equívoco comum consiste em testes destinados a cobrir código escrito por outras pessoas. Normalmente, os testes devem abranger apenas seu código. Por exemplo, se você estiver usando uma biblioteca de elementos gráficos open-source em seu projeto, não precisará testar essa biblioteca.
- Escolher a granularidade certa: por exemplo, se você estiver executando testes de unidade, um teste individual não deverá combinar nem testar várias funções ou métodos. Teste cada função separadamente e depois escreva testes de integração que verificam que 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 deseja executar. Por exemplo, você pode usar Selenium para executar o teste de interface do usuário em vários tipos de sistemas operacionais e navegadores da Web.
Não importa em qual idioma seu aplicativo está escrito, há muitas ferramentas de teste disponíveis para você usar.
Por exemplo, para aplicativos Java, você pode escolher Checkstyle para executar o teste lint e JUnit para realizar testes de unidade.
Neste módulo, usaremos o NUnit para teste de unidade porque ele é popular na comunidade .NET.