Jest Framework Background
Programação

Testes automatizados com o Framework Jest

19.04.2021 12H40

Testes de software são vitais para qualquer rotina de desenvolvimento, e hoje irei abordar sobre o Jest que é um framework Javascript para testes automatizados. Esse poderoso framework dispõe de diversos recursos para auxiliar no processo de criação e execução dos testes automatizados.

Tópicos

Por que usar testes automatizados?

Mas antes de começarmos a abordar sobre a instalação e configuração precisamos falar sobre a importância dos testes automatizados. Afinal, porque eu gastaria meu tempo pensando nos testes e os criando, se posso testar manualmente?

Imagine o seguinte cenário, você desenvolve uma nova feature na sua aplicação e realiza o teste manualmente. Daqui uns dias você precisa mudar algo nessa feature, logo vai precisar testá-la novamente para garantir seu funcionamento. Neste cenário você precisou executar os teste manuais duas vezes, mas essa quantidade por ir ainda além. E pior, caso alguma rotina no teste seja “esquecida”, aquela modificação pode acabar indo para produção com alguma falha em potencial.

Com os testes automatizados é possível criar comandos para realizar os testes toda vez que o código for modificado e com isso evitar muitos problemas. Com isso acaba sendo construindo um roteiro de testes que sempre vai ser seguido, independente de quem estiver atuando no desenvolvimento. Além disso, você pode integrar seus testes com alguma ferramenta de Integração Contínua, como veremos neste mesmo artigo mais pra frente.

Instalação e configuração básica

Primeiro você deve instalar o framework como um dependência de desenvolvimento em seu projeto com o comando abaixo:

npm i -D jest

Após a instalação você deve adicionar ou modificar o comando “test” dentro do arquivo package.json, da seguinte maneira:

// ...
"scripts": {
  "test": "jest --forceExit"
}
// ...

Exemplos de testes automatizados

Com isso você poderá executar no terminal o comando npm test ou yarn test para executar os testes. Ah, e claro, você precisa definir os testes e para criá-los por padrão o nome do arquivo deve ter o sufixo .test.js (ou seja, conter “.test”).

O exemplo abaixo é o trecho de um teste em uma aplicação frontend e está utilizando o puppeteer para realizar os testes. Basicamente, todos os testes unitários como este vão procurar por um determinado “resultado”, seja em uma página ou o retorno de uma chamada para uma API.

const Page = require('./helpers/page');

let page;

beforeEach(async () => {
  page = await Page.build();
  await page.goto('http://localhost:3000');
});

afterEach(async () => {
  await page.close();
});

describe('When logged in', async () => {
  beforeEach(async () => {
    await page.login();
    await page.click('a.btn-floating');
  });

  test('can see blog create form', async () => {
    const label = await page.getContentsOf('form label');

    expect(label).toEqual('Blog Title');
  });

  // ...
});

Caso queira visualizar o exemplo completo, confira no link o arquivo no repositório.

https://github.com/chsjr1996/advanced-node-course/blob/master/tests/blogs.test.js

Ah, e como neste caso trata-se de um teste unitário, é importante dizer que caso seu teste inclua alguma requisição externa você deve “mockar” o serviço responsável por isso. Falarei mais sobre esse termo neste artigo.

Testes de integração vs unitários

Mas afinal, por que temos testes de integração e unitários? Qual a diferença entre eles, e quando usar um ou outro?

De um modo geral, os testes unitários como diz o próprio nome, testam uma unidade (ou parte) do seu software. Neste cenário você não está testando uma funcionalidade por completo, mas sim as partes que a compõe.

Exemplo, o cadastro de um usuário em um sistema geralmente implica em cadastrar seus dados como nome, endereço, foto, entre outros. Em um teste unitário poderíamos apenas validar se o upload da foto está funcionando corretamente no seu software. Ou seja, não nos preocupamos com o cadastro por completo, mas apenas uma parte dele. Em outro teste unitário, podemos verificar se os dados alfanuméricos (nome e endereço) estão funcionando, e assim por diante.

Os testes de integração por sua vez são responsáveis por garantir que as funcionalidades da aplicação estejam funcionando como esperado e é aqui que conseguimos testar uma funcionalidade do início ao fim, e não apenas uma parte. No exemplo citado, o teste criado deverá simular a inserção completa do usuário e apenas se preocupar se o usuário foi cadastrado corretamente ou não.

O que é “Mockar”

O termo “mockar” deriva de um método presente no framework Jest, que é o mock, este método permite criar uma simulação do funcionamento de algum outro método da sua aplicação, de forma que você deve considerar como aquele método deveria funcionar, sua entrada e sua saída.

Mas por que isso é necessário? Bom, quando estamos testando unidades do nosso software não devemos nos preocupar com o escopo de outras unidades, como por exemplo, o método responsável por trazer registros do banco de dados. Neste caso, a forma como esse método funciona pode não importar para unidade que estou testando, sendo necessário apenas manter a garantir do que ele vai retornar, ou seja, “não é como foi feito, mas sim o que vai retornar”.

O mock seria uma representação abstrata daquele método, exemplo, se estiver usando um ORM para base de dados e você quiser criar um teste para o método index de algum controller, então será necessário criar um mock do método findAll (por exemplo) desse ORM, onde o retorno deve ser uma lista com o usuários gerados aleatoriamente. Logo, toda vez que esse teste executar, esperasse que o método index retorne uma lista com os mesmos usuários aleatórios que foram usados no mock, em outras palavras, nós simulamos a forma como o ORM trabalharia, mas o foco era testar se esse método está de fato retornando um resultado válido.

Integração com Travis CI

Imagine um cenário onde o desenvolvedor não acionou os códigos automatizados em seu ambiente local, ou então que por algum motivo os testes passaram mesmo com alguma falha (isso já aconteceu comigo). Nesses cenários o desenvolvedor iria realizar o commit e então teríamos um código defeituoso (ou propenso a falha) no upstream.

O Travis CI é um sistema em nuvem para Integração Continua, mas afinal do que se trata isso? Bom, Integração Continua é a prática de integrar de forma rotineira as alterações realizadas no código fonte de um software, e geralmente é aplicada na ramificação (branch) principal. Dessa forma, cria-se uma garantia maior de que toda atualização de código esteja sendo testada devidamente, e com isso prevenir eventuais problemas.

Com o Travis CI é possível executar rotinas definidas através de um arquivo de configuração. Essas rotinas podem incluir a execução dos testes automatizados, com o objetivo de realizar um double check (já que o desenvolvedor deve também executar os testes localmente) em nuvem.

E assim como citei que já aconteceu comigo, o Travis CI realizou o procedimento configurado que era executar os testes em nuvem e acusou erros nos testes que não foram detectados localmente. Portanto, o Travis CI é um recurso valioso para testes de software. Ah, e vale destacar que para projetos Open Source a ferramenta é gratuita.

Como configurar o TravisCI em meu repositório

Tudo o que você precisa é criar uma conta no site “https://travis-ci.com/“, e vincular alguma conta sua conta de algum repositório de códigos que esteja utilizando, por exemplo, Github. Além disso, você precisa ativar o Travis para os repositórios desejados, para isso clique em seu avatar no canto superior direito do site e vá em Settings (ou configurações), e depois em “Manage repositories on Github” (caso esteja usando Github, por exemplo).

Você será direcionado para seu Github e na parte inferior você pode definir se deseja aplicar o Travis para “Todos os repositórios” ou “Repositórios específicos”.

Feito isso, você deve criar uma arquivo com o nome de .travis.yml na raiz do seu projeto e configurar de acordo com o linguagem e definir comandos que devem ser executados em nuvem. Vou deixar um exemplo para uma aplicação em Node.JS já que o tema é Jest (Javascript), mas você pode usar o Travis com qualquer linguagem que desejar. Link para exemplo.

Agora toda vez que você realizar um push para seu repositório o Travis irá executar os comandos definidos. No exemplo que deixei o Travis vai realizar a instalação, testes e a build da aplicação. Caso dê algum erro o commit ficará assinalado com um “X“, porém se der certo ficará com um visto “” e você poderá conferir os detalhes dentro do site do Travis.

É importante ressaltar que esse prodecimento é mais do que simplesmente verificar commits, você pode implementar um rotina de deploy para o servidor, que só será realizada caso os testes, builds, etc… sejam bem sucedidas. Enfim, as possibilidades são vastas, tudo depende de como vai configurar seu arquivo .travis.yml.

Integração com Coveralls

Um processo muito importante na implementação de testes de software é acompanhar a cobertura de código, e isso pode ser possível através de algum script que consiga verificar se o seu código está bem testado. Mas atenção, a cobertura de código é quantitativa e não qualitativa, ou seja, verifica se “todas” as partes (ou possibilidades) do seu código possuem testes, e não se estes testes estão bem escritos. Portanto, é responsabilidade do desenvolvedor garantir a qualidade dos testes, enquanto a cobertura vai auxiliar no processo de mapeamento de trechos que já possuem testes escritos.

O Jest possui essa funcionalidade e é possível utilizá-la em conjunto com o Coveralls. O Coveralls é um sistema em nuvem capaz de realizar o acompanhamento da cobertura de testes do seu código, e é gratuito para projetos Open Source.

Como configurar o Coveralls em meu repositório

Primeiro você deve criar uma conta no site “https://coveralls.io/” e então vincular a conta do repositório desejado. Logo após isso, será necessário ativar o Coveralls nos repositórios desejados indo na barra lateral em “Add Repos“.

Além disso você deve configurar seu projeto para enviar o status da cobertura de código. Vou deixar aqui uma das formas de se fazer isso com Node.JS usando a biblioteca coveralls.

// ...
"scripts": {
  // ...
  "test:coveralls": "coveralls < coverage/tours-admin/lcov.info"
  // ...
}
// ...

Não se esqueça de executar primeiro o comando para gerar o arquivo “lcov.info“, npm run test:cov -- --browsers=ChromeHeadless . Você pode integrar também com Travis ao colocar o comando “coveralls” de forma que seja executado ao realizar “push” no repositório.

Bônus – Badges

No exemplo (Tours Admin) citado você deve ter notado alguns “cards” no topo do README.md, caso não conheça, esse recurso é chamado de “badge” e você pode obtê-los através dos sites citados (Travis, Coveralls, etc…), ou então gerá-los no site “https://shields.io/“.

Conclusão

Lembre-se sempre, um software bem testado é um software sem surpresas, então os testes automatizados vão garantir uma maior integridade. Claro, isso não descarta alguns testes manuais, ou a supervisão de um time de QA, ou a própria experiência dos usuários. A ideia aqui é amenizar possíveis falhas de lógica em seu código te alertando para que as correções cabíveis sejam aplicadas antes que o software apresente estas falhas aos usuários finais.

Referências e menção

Um agradecimento ao Felipe Renan (CodeEasy) pelas sugestões de melhorias e correções no texto. Confira o trabalho dele nos links abaixo:

Bom, isso é tudo, e embora eu tenha tentado resumir ao máximo, espero que este artigo tenha lhe ajudado. E se gostou, por favor, não esqueça de compartilhar!

Criador do blog SourceVortex, apaixonado em distribuições Linux e por aprender novas tecnologias, buscando também sempre aperfeiçoar os conhecimentos já obtidos.

Tags: