Como criar um teste unitário envolvendo timers | Angular
Marcelo Ribas Vismari -
Criar testes unitários eficazes é crucial para garantir a robustez e confiabilidade de um código. Por aqui já abordamos alguns exemplos de como construir testes unitários envolvendo alguns componentes, mas ainda não mostrei um exemplo envolvendo temporizadores, como o setTimeout, setInterval ou timer e interval do RxJS.
Para construir este exemplo, utilizei um projeto que usa a versão 16 do Angular, mas a lógica empregada é a mesma para outras versões. Deixei o link do repositório no final do texto.
O componente com o Timer
Para criar o cenário de estudo, construí um componente bem simples, similar a um cronômetro:
O código fonte do componente ficou da seguinte forma:
Construção dos testes unitários
Para construir os testes unitários vamos utilizar Jasmine, mas vou comentar sobre o Jest que também possui recursos similares para este cenário envolvendo um interval.
A estrutura básica do teste ficará da seguinte forma:
O primeiro método a ser testado é o iniciarTimer. Este método é bastante simples, atribuindo valores a duas variáveis e iniciando um intervalo. Após a execução, esperamos que, por exemplo, o método atualizarTimer seja chamado três vezes após 3 segundos, pois configuramos o intervalo para executar a cada 1 segundo.
Para realizar esse teste, não é necessário aguardar os 3 segundos reais. Podemos implementar um "relógio" simulado ("mock"), que substitui o controle padrão de data e hora. Ao utilizar jasmine.clock().install(), temos a capacidade de estabelecer a data atual, atribuindo-a ao valor de new Date(), e ajustá-la, por exemplo, para 2020-01-01T12:00:00.000Z. Posteriormente, podemos avançar no tempo nesse "relógio" simulado conforme necessário, utilizando o comando jasmine.clock().tick().
Para ficar mais claro, veja o exemplo abaixo onde estamos simulando um valor para o new Date():
const dataMock = new Date('2020-01-01T12:00:00.000Z');
jasmine.clock().install();
jasmine.clock().mockDate(dataMock);
console.log('[1]', (new Date()).toISOString());
// [1], 2020-01-01T12:00:00.000Z
jasmine.clock().tick(3000);
console.log('[2]', (new Date()).toISOString());
// [2], 2020-01-01T12:00:03.000Z
Agora que sabemos como controlar a linha do tempo durante os testes unitários, podemos escrever o seguinte teste unitário para o método iniciarTimer:
Na sequência vamos criar um teste para o método atualizarTimer. Este método calcula a diferença de tempo em segundos entre a data corrente e a data que consta na variável dataInicioTimer. Então podemos adicionar um valor conhecido em dataInicioTimer e novamente simular a linha do tempo para verificar se o cálculo que o método está fazendo é correto.
JEST
Utilizando o Jest a lógica é a mesma, o que muda são os métodos que o Jest disponibiliza:
Considerações
A possibilidade de simular e controlar o relógio do JavaScript, como no Jasmine ou Jest, proporciona uma abordagem valiosa para testes unitários mais eficientes e controlados. Essa prática é particularmente benéfica para avaliar funcionalidades que envolvem timeouts, intervals e operações dependentes do tempo, resultando em testes mais rápidos, confiáveis e independentes do ambiente externo.
Link do projeto utilizando Jasmine e Jest respectivamente: