Utiliser Moq pour simuler une méthode asynchrone pour un test unitaire

Je teste une méthode pour un service qui effectue un appel API Web. L’utilisation d’un HttpClient normal fonctionne bien pour les tests unitaires si HttpClient également le service Web (situé dans un autre projet de la solution) localement.

Cependant, lorsque je vérifie mes modifications, le serveur de génération n’aura pas access au service Web, ce qui entraînera l’échec des tests.

J’ai conçu une solution pour mes tests unitaires en créant une interface IHttpClient et en implémentant une version que j’utilise dans mon application. Pour les tests unitaires, je réalise une version simulée avec une méthode de publication asynchrone simulée. Voici où j’ai rencontré des problèmes. Je veux retourner un HttpStatusResult OK pour ce test particulier. Pour un autre test similaire, je vais retourner un mauvais résultat.

Le test sera exécuté mais ne sera jamais terminé. Il est suspendu à l’attente. Je suis nouveau dans la programmation asynchrone, les delegates et Moq lui-même et j’ai cherché SO et Google pendant un certain temps en apprenant de nouvelles choses, mais je n’arrive toujours pas à surmonter ce problème.

Voici la méthode que je tente de tester:

 public async Task QueueNotificationAsync(IHttpClient client, Email email) { // do stuff try { // The test hangs here, never returning HttpResponseMessage response = await client.PostAsync(uri, content); // more logic here } // more stuff } 

Voici ma méthode de test unitaire:

 [TestMethod] public async Task QueueNotificationAsync_Completes_With_ValidEmail() { Email email = new Email() { FromAddress = "bob@example.com", ToAddress = "bill@example.com", CCAddress = "brian@example.com", BCCAddress = "ben@example.com", Subject = "Hello", Body = "Hello World." }; var mockClient = new Mock(); mockClient.Setup(c => c.PostAsync( It.IsAny(), It.IsAny() )).Returns(() => new Task(() => new HttpResponseMessage(System.Net.HttpStatusCode.OK))); bool result = await _notificationRequestService.QueueNotificationAsync(mockClient.Object, email); Assert.IsTrue(result, "Queue failed."); } 

Qu’est-ce que je fais mal?

Merci de votre aide.

Vous créez une tâche mais ne la lancez jamais, alors elle ne se termine jamais. Cependant, ne vous contentez pas de lancer la tâche – utilisez Task.FromResult ce qui vous donnera une tâche déjà terminée:

 ... .Returns(Task.FromResult(new HttpResponseMessage(System.Net.HttpStatusCode.OK))); 

Notez que vous ne testerez pas l’asynchronisme réel de cette façon – si vous voulez faire cela, vous devrez faire un peu plus de travail pour créer une Task que vous pourrez contrôler de manière plus fine … mais c’est quelque chose pour un autre jour.

Vous pouvez également envisager d’utiliser un faux pour IHttpClient plutôt que de vous moquer de tout: cela dépend vraiment de la fréquence à laquelle vous en avez besoin.