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