Aller au contenu principal

Mocker les méthodes des interfaces par spyOn

06 juin 2023

TL;DR

Mocker les méthodes des interfaces par spyOn (exemple : jest.spyOn(httpClientService, 'get').mockResolvedValue(...))

Contributeurs

Suxue Li, Julie Brunetto, Guillaume Moizan, Gauthier Fiorentino, Dorian De Rosa, Fred Nobre

Statut

Accepté

Contexte

Plusieurs manières de mocker / stubber une dépendance, exemple avec la méthode get sur le httpClientService :

  • (httpClientService.get as jest.Mock).mockResolvedValue(...)
  • jest.spyOn(httpClientService, 'get').mockResolvedValue(...)
  • anHttpClientService({ get: jest.fn(async () => ({...}) })

Après discussion, l'équipe s'accorde sur :

  • (httpClientService.get as jest.Mock).mockResolvedValue(...) -> Ne plus le faire car plus besoin de redéfinir manuellement le type

L'équipe est divisée entre le jest.spyOn et l'override à l'instanciation de la classe, pour des raisons de préférences subjectives de lecture.

En utilisation, la méthode l'override à l'instanciation de la classe (anHttpClientService({ get: jest.fn(async () => ({...}) })) présente un défaut : lorsqu'on veut mocker la même méthode pour plusieurs appels, par exemple deux appels, on est obligé d'écrire :

const errorManagementService = anErrorManagementService({
handleFailureError: jest.fn(() => createFailure(ErreurMétier.SERVICE_INDISPONIBLE))
.mockImplementationOnce(() => createFailure(ErreurMétier.DEMANDE_INCORRECTE))
.mockImplementationOnce(() => createFailure(ErreurMétier.CONTENU_INDISPONIBLE),
});

De plus, cette méthode présente l'inconvénient de ne pas pouvoir retourner un type union comme Either (Failure | Success) que nous utilisons beaucoup dans le projet. Le type étant inféré de l'implémentation qu'on donne au jest.fn, si cette implémentation retourne une Failure comme l'exemple ci-dessus, .mockImplementationOnce(() => createSuccess({...}) ne sera pas accepté.

Nous ne voulons pas mélanger deux méthodes de mock.

Décision

Pour éviter d'avoir deux manières de faire, la préférence est donnée à la méthode : jest.spyOn(httpClientService, 'get').mockResolvedValue(...) (= instancier la fixture de l'interface, et faire un spyOn dessus pour chaque mock qu'on veut mettre en place)

L'équipe s'accorde aussi sur le fait de ne pas initialiser des méthodes / valeurs testées dans un beforeEach pour garder des tests autoportants.

Conséquences

Les :

  • (httpClientService.get as jest.Mock).mockResolvedValue(...)
  • anHttpClientService({ get: jest.fn(async () => ({...}) })

et équivalent sur autres interfaces / méthodes sont dépréciés

Autres pistes explorées