91 votes

Attendre l'appel d'une méthode Async Void pour les tests unitaires

J'ai une méthode qui ressemble à ceci :

private async void DoStuff(long idToLookUp)
{
    IOrder order = await orderService.LookUpIdAsync(idToLookUp);   

    // Close the search
    IsSearchShowing = false;
}    

//Other stuff in case you want to see it
public DelegateCommand<long> DoLookupCommand{ get; set; }
ViewModel()
{
     DoLookupCommand= new DelegateCommand<long>(DoStuff);
}    

J'essaie de le tester de la manière suivante :

[TestMethod]
public void TestDoStuff()
{
    //+ Arrange
    myViewModel.IsSearchShowing = true;

    // container is my Unity container and it setup in the init method.
    container.Resolve<IOrderService>().Returns(orderService);
    orderService = Substitute.For<IOrderService>();
    orderService.LookUpIdAsync(Arg.Any<long>())
                .Returns(new Task<IOrder>(() => null));

    //+ Act
    myViewModel.DoLookupCommand.Execute(0);

    //+ Assert
    myViewModel.IsSearchShowing.Should().BeFalse();
}

Mon assert est appelé avant que j'aie terminé le LookUpIdAsync simulé. Dans mon code normal, c'est exactement ce que je veux. Mais pour mon test d'unité, je ne veux pas cela.

Je suis en train de passer de l'utilisation de BackgroundWorker à Async/Await. Avec le BackgroundWorker, cela fonctionnait correctement car je pouvais attendre que le BackgroundWorker se termine.

Mais il ne semble pas y avoir de moyen d'attendre une méthode async void...

Comment puis-je tester cette méthode à l'unité ?

5voto

Velimir Points 76

La réponse fournie teste la commande et non la méthode asynchrone. Comme mentionné ci-dessus, vous aurez besoin d'un autre test pour tester également cette méthode asynchrone.

Après avoir passé un peu de temps avec un problème similaire, j'ai trouvé une attente facile pour tester une méthode asynchrone dans un test unitaire en l'appelant simplement de manière synchrone :

    protected static void CallSync(Action target)
    {
        var task = new Task(target);
        task.RunSynchronously();
    }

et l'utilisation :

CallSync(() => myClass.MyAsyncMethod());

Le test attend sur cette ligne et continue une fois que le résultat est prêt, de sorte que nous pouvons affirmer immédiatement après.

2voto

Modifiez votre méthode pour qu'elle renvoie une tâche et vous pourrez utiliser Task.Result.

bool res = configuration.InitializeAsync(appConfig).Result;
Assert.IsTrue(res);

-1voto

datchung Points 1586

J'ai eu un problème similaire. Dans mon cas, la solution a été d'utiliser Task.FromResult dans l'installation moq pour .Returns(...) comme suit :

orderService.LookUpIdAsync(Arg.Any<long>())
    .Returns(Task.FromResult(null));

Par ailleurs, Moq dispose également d'un ReturnsAysnc(...) méthode.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X