De volta para o futuro: usando Clock para manipular o tempo nos seus testes
Conhecer a linguagem de programação muitas vezes não é só essencial para criar um bom código mas também para criar bons testes.
Um destes conhecimentos que pode ser estranho para uma parte significativa dos desenvolvedores Java 8+ é a classe Clock.
A classe Clock é responsável por providenciar o tempo atual, que no Java é chamado de instante (instant). Quando fazemos, por exemplo, um LocalDate.now(), o Java lê o instante do relógio do seu computador. Porém, podemos manipular este instante colocando um Clock diferente no lugar dele.
Usando o exemplo do LocalDate.now(), podemos “enganá-lo” quanto ao instante em que ele está, bastando passar um Clock para o método now() como parâmetro, da seguinte forma: LocalDate.now(clock).
Agora, como posso manipular o tempo (ou instante) com o Clock?
Existem diferentes maneiras. Uma das mais simples é esta:
Porém, isto levanta questões práticas de como usá-lo:
- Como passar o Clock para o método now() em um projeto de verdade?
- Como alternar o instante real com o instante que quero no meu teste?
A melhor prática e oficialmente recomendada para lidar com este cenário é usar a injeção de dependência por construtor, assunto este já abordado em outro texto.
Basicamente, você cria o objeto Clock como uma dependência injetável e passa para dentro do construtor da classe. Isto vai permitir que o Clock seja injetado pelo seu framework de injeção e, para o teste unitário, permitirá ao desenvolvedor instanciar o Clock com o instante no tempo que preferir.
Usando…
Vamos mostrar abaixo um exemplo de como conseguimos montar este cenário todo usando o framework Spring.
Sua classe que receberá a injeção de Clock ficaria assim:
O teste unitário de uma classe assim é igualmente simples. Basta instanciar a classe e depois passar o Clock como parâmetro:
Agora vamos criar uma classe injetável (bean) a partir do Clock:
Com isto, temos tudo pronto: o código que receberá a injeção do Clock, o teste unitário e o Clock injetável.
… e abusando
Se você ainda quiser abusar do Clock, você pode aplicar este mesmo conceito para os seus testes de integração, criando cenários inteiros de teste manipulando o tempo, mockando o Clock com @MockBean
e alterando o instante dele.
Já implementei vários testes automatizados, executando diversos cenários, usando este recurso. A flexibilidade proporcionada por esta estratégia para criar testes que precisam de dados cadastrados no passado é excelente.
… e abusando²
Agora, se você deseja estressar ao máximo os limites de um teste com Clock, fica a dica: você pode criar um serviço qualquer (Rest, Servlet, você escolhe!), desde que fique disponível apenas em ambiente de desenvolvimento, que possa permitir manipular a data da aplicação da maneira que quiser, bastando passar a data desejada neste serviço disponibilizado. Lembra daqueles testes que seu QA reclamava que eram difíceis de se fazer, pois dependiam de registros passados? Então, não mais :).
Este tipo de funcionalidade basicamente envolve a alteração em tempo de runtime de beans do Spring. Criei um repositório com uma implementação funcional usando um bean Delorean para fazer o meio de campo com o Clock, apenas para ilustrar esta possibilidade. Vocês podem conferir mais detalhes e algumas observações sobre a implementação no próprio repositório.
Bem, é isto. Para testes que uma máquina do tempo viria a calhar, o Clock irá te ajudar.