Comment puis-je tester par unité cette méthode asynchrone qui lève (correctement) une exception?

J’ai la méthode suivante dans une interface ..

Task<SearchResult> SearchAsync(TU searchOptions); 

fonctionne très bien.

Maintenant, j’essaie de faire un test unitaire pour tester quand quelque chose ne va pas – et le code lève une exception.

Dans ce cas, j’ai configuré ma méthode pour HttpRequestException une HttpRequestException . Mon test d’unité ne dit pas que j’ai jeté cette exception.

 var result = Should.Throw (async () => await service.SearchAsync(searchOptions)); 

le message d’erreur du test unitaire est

Shouldly.ChuckedAWobbly
var résultat = devrait
jeter
System.Net.Http.HttpRequestException
mais ne

Le cadre des assertions dit donc: vous vous attendez à une exception, mais aucune n’a été lancée.

Quand je passe le code, l’exception est levée à 100%.

Quelqu’un peut-il voir ce que j’ai mal fait avec mon code de test d’unité, s’il vous plaît?

Le problème est que votre cadre d’assertion ne comprend pas les méthodes asynchrones. Je vous recommande de soulever un problème avec eux.

En attendant, vous pouvez utiliser le source de Should.Throw pour écrire votre propre MyShould.ThrowAsync :

 public static async Task ThrowAsync(Func actual) where TException : Exception { try { await actual(); } catch (TException e) { return e; } catch (Exception e) { throw new ChuckedAWobbly(new ShouldlyMessage(typeof(TException), e.GetType()).ToSsortingng()); } throw new ChuckedAWobbly(new ShouldlyMessage(typeof(TException)).ToSsortingng()); } 

Et utilisez-le comme tel:

 var result = await MyShould.ThrowAsync (async () => await service.SearchAsync(searchOptions)); 

ou le légèrement plus simple et équivalent:

 var result = await MyShould.ThrowAsync (() => service.SearchAsync(searchOptions)); 

Le test unitaire du code / des fonctionnalités asynchrones est assez difficile. Je me lance moi-même dans les tests asynchrones des unités et je rencontre les mêmes problèmes que vous.

J’ai trouvé les deux ressources suivantes très utiles:

  • Meilleures pratiques en programmation asynchrone – il aborde le sujet de l’async et des problèmes rencontrés pour le tester.
  • Le test unitaire asynchrone dans le mauvais sens et le test unitaire asynchrone dans le bon sens – plonge dans le sujet, montre les problèmes que vous allez rencontrer et la manière de configurer le test.

Le problème est que le lambda passé renvoie une tâche. L’exception levée ne peut être observée par Should.Throw s’il attend que cette tâche soit terminée, ce qu’elle ne fait apparemment pas. En guise de .Wait contournement, vous pouvez. .Wait vous- .Wait la tâche renvoyée par SearchAsync .

mstest (la structure de test Visual Studio intégrée) prend en charge les tests asynchrones depuis Visual Studio 2012. Vous pouvez en principe simplement modifier la déclaration de la méthode de test en remplaçant “void” par “async Task”.

 [TestMethod] [ExpectedException(typeof(System.Net.Http.HttpRequestException))] public async Task SomeTest() { await service.SearchAsync(searchOptions); } 

Vous utilisez probablement un autre framework de test unitaire, mais vous ne savez pas lequel. Consultez sa documentation pour voir si elle prend en charge les tests asynchrones.

NUnit 2.6.3 semble également supporter les tests asynchrones.

edit : vous utilisez donc xUnit. Ce problème particulier a été résolu pour xUnit 2.0 . C’est actuellement encore alpha cependant.

L’exception est renvoyée sur un thread différent de celui sur lequel votre test unitaire est exécuté. La structure de test unitaire ne peut anticiper les exceptions que sur son propre thread.

Je vous suggère de tester l’exception sur une version synchrone du service.

Testez-le comme ceci:

 var result = Should.Throw (() => service.SearchAsync(searchOptions).Result); 

Ou:

 var result = Should.Throw (() => service.SearchAsync(searchOptions).Wait()); 

Sinon, votre Should.Throw renvoyé avant la fin du lambda async .