Fala pessoal, no PET Redação deste mês iremos abordar e entender melhor sobre um dos conhecimentos que têm sido cobrados nas vagas do mercado de desenvolvimento de software, os testes e, principalmente, a automatização deles.
O que é automatização de testes de software?
Primeiramente, é importante entender melhor o que é automatização de testes. Por mais que a resposta pareça um pouco óbvia, é necessário entender o processo de um teste durante um desenvolvimento de software. Por exemplo, pode-se testar um código manualmente rodando ele, comparando resultados e analisando possíveis bugs, porém o próprio teste manual está sujeito a erros e quando trata-se de um sistema mais complexo, uma API, etc. realizar testes automatizados é mais crucial ainda.
Um teste automatizado consiste em desenvolver outra parte de código que realize um teste, que seria feito manualmente, de forma automática.
O processo de um teste é simples: existe um código ou uma função, existe um retorno esperado dessa aplicação e um resultado se o foi bem sucedido ou resultou em uma falha. Baseado nisso, pode-se alterar o código e fazer correções de bugs ou implementar novos testes.
Por que implementar testes?
Outro tópico importante para entrar é o porquê da implementação de testes automatizados. O primeiro ponto é o tempo, pois, apesar de a automatização de testes ter um tempo de desenvolvimento, a longo prazo o programador perderá menos tempo testando manualmente.
Outro ponto é a facilidade de encontrar novos bugs, já que além dos próprios testes automatizados já fazerem isso, o próprio desenvolvedor, quando está implementando os testes, consegue visualizar melhor o que pode ocasionar em um bug futuramente.
Por último, muitos projetos maiores e mais complexos utilizam os testes automatizados para melhorar o fluxo de trabalho. Por exemplo, quando é feito um commit em um repositório do Github e uma aplicação para testar testar é rodada antes de fazer o deploy da aplicação na produção, não permitindo que bugs e erros cheguem no ambiente de produção e cause problemas ao sistema que está online.
Tipos de teste
Agora, pode-se entrar nos tipos de testes. Existem diversos tipos de testes de software, porém vamos focar nos testes mais comuns de serem desenvolvidos em aplicações: teste unitários e testes de integração.
Testes Unitários
Testam unidades menores de uma aplicação, de forma isolada, para ver se cada unidade do software está funcionando adequadamente. Desse modo, testes unitários podem ser implementados rapidamente e normalmente já auxiliam durante o desenvolvimento de uma função, um método, etc.
Testes de Integração
Testam diversas unidades que possuem dependência entre si, para ver se a aplicação funciona de forma integrada. Esses testes são realizados mesmo se todos os testes unitários passaram.
Implementação
Passado a parte teórica, pode-se entrar na parte prática. Para desenvolver nosso código e nossos testes vamos utilizar Javascript e a IDE Visual Studio Code. Para isso, será necessário instalar o Node.js, que está disponível neste link. Para realizar nossos testes, vamos utilizar um framework chamado Jest, que possui diversas funções para automatizar os testes de forma simples.
Após instalar o Node.Js, crie uma pasta para conter o projeto Node. Para iniciar um projeto Node, utiliza-se o gerenciador de pacotes do Node.Js, o npm. No terminal do Visual Studio Code, acesse a pasta que deve ser criado o projeto e rode o seguinte comando:
npm init – y
Esse comando vai criar um arquivo chamado package.json, tem algumas informações do nosso projeto, alguns scripts que serão necessários futuramente e as dependências do projeto, que são os frameworks, bibliotecas que podemos instalar nessa aplicação.
Ainda utilizando o npm, instale o Jest utilizando o seguinte comando:
npm install jest
Agora, no package.json é possível visualizar o Jest como uma dependência do projeto. Para rodar os testes da nossa aplicação futuramente, deve-se alterar o script test para jest no package.json, ficando assim:
scripts”: {
“test”: “jest”
}
Finalizado todas as configurações de ambiente, iremos criar um arquivo app.js para implementar as funções que serão testadas. A primeira será uma simples função que retorna a soma de dois números. Como no código abaixo:
function soma (n1, n2) {
return n1 + n2;
}
module.exports = { soma };
Na primeira parte do código, foi implementado o código, depois há um module.exports, que é utilizado para exportar a função soma para usar ela dentro dos testes.
Agora, para implementar o primeiro teste unitário, deve-se criar um arquivo app.test.js. A parte de .test no nome do arquivo serve para o Jest identificar que o arquivo é um teste e executá-lo. Dentro do arquivo terá o seguinte código:
const { soma } = require(‘./app’);
test(‘Deve somar dois números’, () => {
const resultado = soma(10, 15);
expect(resultado).toBe(25);
});
Na primeira linha é feita a importação da função soma do arquivo app.ts. Após isso, usamos uma função padrão do Jest, chamada test, para criar um teste. Dentro dessa função, o primeiro parâmetro é a descrição do teste, nesse caso “Deve somar dois números”. Já o segundo parâmetro é um função, que é o teste em si, contendo uma const que recebe o resultado da soma e uma outra função do Jest chamada expect, que, basicamente, faz uma comparação do retorno da função soma com um valor informado. Essa parte pode ser traduzida como: Espera-se que resultado seja 25. Para rodar esse teste, deve-se utilizar o comando abaixo, que foi atualizado anteriormente:
npm test
Caso tudo tenha sido implementado corretamente, o teste deve ter um status de passed. Como na imagem abaixo:
Agora, iremos implementar outra função dentro do app.js, para realizar a validação de dois parâmetros, que depois será utilizada dentro da função soma para transformá-la em um teste de integração. O arquivo app.js deve ficar assim:
function validacao(n1, n2) {
if(!n1 || !n2 || isNaN(n1) || isNaN(n2)) {
return false;
}
return true;
}
function soma (n1, n2) {
return n1 + n2;
}
module.exports = { soma, validacao };
A função validacao possui um if que vai retornar false, caso seja passado algum valor vazio ou não seja um número, senão retorna true. A partir disso, pode-se implementar um teste unitário para testar os dois casos. Desenvolvendo o teste no arquivo app.test.js, ficará assim:
const { soma, validacao } = require(‘./app’);
test(‘Deve somar dois números’, () => {
const resultado = soma(10, 15);
expect(resultado).toBe(25);
});
test(‘Deve retornar a validação correta’, () => {
// retorna falso por que possui valor vazio
expect(validacao(3, null)).toBe(false);
// retorna falso por que possui valor não numérico
expect(validacao(3, “a”)).toBe(false);
expect(validacao(10, 15)).toBe(true);
});
Dentro do teste de validação há 3 chamadas para testar todos os casos possíveis. No primeiro caso, passamos um valor null para a função validacao, esperando que retorne false. No segundo caso, enviamos um carácter para a função validacao, esperando que retorne false também. No último caso, enviamos valores corretos para a função, esperando que ela retorne true dessa vez. Rodando npm test novamente, pode-se visualizar que os dois testes resultarão em passed, igual na imagem abaixo:
Depois de implementar dois testes de integração, vamos transformar o teste de soma em um teste de integração, a partir da adição da função de validação dentro da função de soma. Dessa forma:
function soma (n1, n2) {
if(!validacao(n1, n2))
throw “Valores Inválidos”;
return n1 + n2;
}
Agora, caso seja passado valores inválidos, o programa vai gerar um erro a partir do throw. Dessa forma, a função soma possui dependência de outra função, logo o primeiro teste que implementamos virou um teste de integração. Porém, ainda pode ser feito algumas alterações no teste de soma para testar caso seja passado valores inválidos. O teste de soma ficará assim:
test(‘Deve somar dois números’, () => {
const resultado = soma(10, 15);
expect(resultado).toBe(25);
expect(() => {
soma(3, “a”)
}).toThrow(“Valores Inválidos”);
});
Nesse caso, adicionamos outro expect passando valores inválidos, esperando que seja retornado um erro. Rodando npm test, pode-se ver que o teste ainda está passando, como na imagem abaixo:
Conclusão
Com isso, foi possível compreender mais sobre testes, o porquê de implementá-los e como colocá-los em prática com a implementação do projeto com Javascript, Node.js e Jest. Nos links abaixo estão alguns materiais e vídeos utilizados para escrever a redação, além de outros testes que não foram mencionados.
Referências
Unit tests, Integration tests & e2e tests
Testes no NodeJS aplicando TDD com Jest
Teste de software: Introdução, Conceitos Básicos e Tipos de Testes
Francisco Palermo