I have a method that looks like this:
private async void DoStuff(long idToLookUp)
{
IOrder order = await orderService.LookUpIdAsync(idToLookUp);
The provided answer tests the command and not the async method. As mentioned above you'll need another test to test that async method as well.
After spending some time with a similar problem i found an easy wait to test an async method in a unit test by just calling in synchronously:
protected static void CallSync(Action target)
{
var task = new Task(target);
task.RunSynchronously();
}
and the usage:
CallSync(() => myClass.MyAsyncMethod());
The test waits on this line and continues after the result is ready so we can assert immediately afterwards.
I had a similar issue. In my case, the solution was to use Task.FromResult
in the moq setup for .Returns(...)
like so:
orderService.LookUpIdAsync(Arg.Any<long>())
.Returns(Task.FromResult(null));
Alternatively, Moq also has a ReturnsAysnc(...)
method.
I figured out a way to do it for unit testing:
[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>();
var lookupTask = Task<IOrder>.Factory.StartNew(() =>
{
return new Order();
});
orderService.LookUpIdAsync(Arg.Any<long>()).Returns(lookupTask);
//+ Act
myViewModel.DoLookupCommand.Execute(0);
lookupTask.Wait();
//+ Assert
myViewModel.IsSearchShowing.Should().BeFalse();
}
The key here is that because I am unit testing I can substitute in the task I want to have my async call (inside my async void) to return. I then just make sure the task has completed before I move on.
You should avoid async void
. Only use async void
for event handlers. DelegateCommand
is (logically) an event handler, so you can do it like this:
// Use [InternalsVisibleTo] to share internal methods with the unit test project.
internal async Task DoLookupCommandImpl(long idToLookUp)
{
IOrder order = await orderService.LookUpIdAsync(idToLookUp);
// Close the search
IsSearchShowing = false;
}
private async void DoStuff(long idToLookUp)
{
await DoLookupCommandImpl(idToLookup);
}
and unit test it as:
[TestMethod]
public async Task 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
await myViewModel.DoLookupCommandImpl(0);
//+ Assert
myViewModel.IsSearchShowing.Should().BeFalse();
}
My recommended answer is above. But if you really want to test an async void
method, you can do so with my AsyncEx library:
[TestMethod]
public void TestDoStuff()
{
AsyncContext.Run(() =>
{
//+ 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();
}
But this solution changes the SynchronizationContext
for your view model during its lifetime.
The only way I know is to turn your async void
method to async Task
method
Change your method to return a Task and you can use Task.Result
bool res = configuration.InitializeAsync(appConfig).Result;
Assert.IsTrue(res);