Testes - Mockando métodos e propriedades de libs externas com Jest, no TypeScript
No desenvolvimento de software, muitas vezes nos deparamos com a necessidade de testar a integração do código que escrevemos com bibliotecas externas. Para isso, os testes devem ser limitados ao nosso código e é recomendado que as partes que utilizamos destas bibliotecas sejam mockadas, ou simuladas. Assim, não dependeremos de fatores alheios ao nosso controle, como o retorno de requisições feitas a API’s reais.
Ao considerar como estas simulações podem ser feitas, apresentarei exemplos usando o Jest como framework de testes, que será utilizado para mockar partes do Axios, uma biblioteca que efetua requisições HTTP. O código estará em Typescript.
Veja o código abaixo:
import axios from 'axios’
jest.mock('axios')
const mockedAxios = axios as jest.Mocked<typeof axios>
mockedAxios.post.mockResolvedValue(axiosPostResponse)
A linha jest.mock('axios') cria um mock do módulo 'axios', substituindo as chamadas reais para o módulo por uma versão simulada, controlada pelos testes.
Em seguida, const mockedAxios = axios as jest.Mocked cria uma constante mockedAxios, que é do tipo jest.Mocked. Isso permite que a variável tenha acesso às funcionalidades de simulação fornecidas pelo Jest.
Por fim, mockedAxios.post.mockResolvedValue(axiosPostResponse) define o comportamento simulado da função post, do objeto mockedAxios. Neste caso, a simulação é configurada para retornar uma promessa (Promise) resolvida com o valor axiosPostResponse, que é o retorno simulado para fins de teste. Isso significa que quando o código chamar mockedAxios.post(), ele receberá uma promessa que, quando resolvida, retornará o valor axiosPostResponse.
Uma dúvida que poderá surgir:
Qual a necessidade da linha const mockedAxios = axios as jest.Mocked? Sabemos que depois de jest.mock('axios') qualquer referência ao axios estará apontando para o mock do módulo. Então, por que não usar diretamente axios.post.mockResolvedValue() para mockar um retorno para o método post?
Acontece que o mock do Axios, resultante de jest.mock('axios'), contém a assinatura do módulo do Axios, incluindo o método post. Porém, neste módulo não existe o método mockResolvedValue(), que é um recurso do Jest. Logo, axios.post.mockResolvedValue() seria impossível.
A linha const mockedAxios = axios as jest.Mocked, assegura que a constante mockedAxios contenha um objeto com a assinatura daquele exportado pelo módulo do Axios (incluindo o método post) e, ao mesmo tempo, as funcionalidades do Jest, como mockResolvedValue. Então, será possível:
- mockar o retorno de um método como axios.post() simplesmente usando mockedAxios.post.mockResolvedValue(axiosPostResponse).
- mockar a implementação de qualquer método. Ex.: mockedAxios.getUri.mockImplementation(()=>"any_uri")
O mesmo pode ser feito com as propriedades do módulo. Com essas técnicas em mãos, você terá um controle total sobre as interações com o axios, tornando seus testes mais confiáveis e independentes de recursos externos.