amplifier
amplifier

Reputation: 1833

Await asynchronous command in unit test

I use async commands based on https://msdn.microsoft.com/en-us/magazine/dn630647.aspx

An executor of the command looks like this:

(package) =>
{
    return Task.Run(() =>
    {
        dataProvider.Save(package);
        // emulate long running operation
        for (int i = 0; i < 5000000; ++i)
        {
            string[] ar = new string[1000];
        }
}).ContinueWith(t =>
{
    messagingService.Send(new PackageSavedMessage
    {
        Id = package.Id,
        Name = package.Name,
    });
}, TaskScheduler.FromCurrentSynchronizationContext());

It works well when I click on save button in the application, i.e. it asynchronously waits, then ContinueWith fires.

But when I try to call it from unit test

[Test]
public async Task SaveCommand_Test()
{
    using (var scope = _container.BeginLifetimeScope())
    {
        var vm = scope.Resolve<MainViewModel>();
        AsyncCommandBase acb = vm.PackageViewModels[0].SaveCommand as AsyncCommandBase;
        SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
        await acb.ExecuteAsync(package);
    }
}

ContinueWith fires immediately, not waiting for task finished

If I don't set SynchronizationContext, I get an error

The current SynchronizationContext may not be used as a TaskScheduler.

Upvotes: 0

Views: 152

Answers (1)

Stephen Cleary
Stephen Cleary

Reputation: 457472

Your executor shouldn't need to use ContinueWith; a more modern await would work just as well (note that await will automatically capture and resume its context, so no explicit TaskScheduler is necessary):

async (package) =>
{
  await Task.Run(() =>
  {
    dataProvider.Save(package);
    // emulate long running operation
    for (int i = 0; i < 5000000; ++i)
    {
      string[] ar = new string[1000];
    }
  });
  messagingService.Send(new PackageSavedMessage
  {
    Id = package.Id,
    Name = package.Name,
  });
}

Upvotes: 2

Related Questions