Reputation: 10563
I need to unit test a method that looks roughly like this:
public async Task DoStuffAsync()
{
var tasks = { dependency.FooAsync(), dependency.BarAsync() };
await Task.WhenAll(tasks);
}
My first approach (using Moq) was like this:
dependency.Setup(d => d.FooAsync()).Returns(Task.FromResult(default(object)));
dependency.Setup(d => d.BarAsync()).Returns(Task.FromResult(default(object)));
await systemUnderTest.DoStuffAsync();
dependency.Verify(d => d.FooAsync(), Times.Once);
dependency.Verify(d => d.BarAsync(), Times.Once);
But this won't do, since if I change the method to something dumb like this:
public async Task DoStuffAsync()
{
var tasks = { dependency.FooAsync(), dependency.BarAsync() };
await tasks[0];
}
the test won't fail. How do I assert that the tasks were awaited?
EDIT:
I think this solution to this problem could be analogous to mine:
let's say I want to test this method for failure, i.e. one of the tasks throws and I want to assert that the exception is propagated. I need to check that for all the tasks, but there could be a dozen tasks awaited by Task.WhenAll
. I'd then have to write a dozen tests, each of them would have a different, single task throw an exception, to make sure that all of them are correctly propagated. And writing a dozen same-y tests doesn't sound like a good thing. If I could just assert that all the tasks are awaited - that would solve my problem, as I can trust the async framework to propagate if an error occurs.
Upvotes: 0
Views: 2945
Reputation: 32445
You give very little context (programming is all about context :)).
In you particular case if you want check that DoStuffAsync
await all tasks returned by dependencies throw exceptions and await for them
For .NET 4.5.1 create helper method to create task with an exception.
static Task CreateTaskWithException(string exceptionMessage)
{
var taskSource = new TaskCompletionSource<object>();
var exception = new Exception(exceptionMessage);
taskSource.SetException(exception);
return taskSource.Task;
}
If you have multiple dependencies you can test for await - you can simple test all of them at once
dependency.Setup(d => d.FooAsync()).Returns(CreateTaskWithException("Foo"));
dependency.Setup(d => d.BarAsync()).Returns(CreateTaskWithException("Bar"));
dependency.Setup(d => d.FizzBuzzAsync()).Returns(CreateTaskWithException("FizzBuzz"));
var expectedErrors = new[] { "Foo", "Bar", "FizzBuzz" };
string[] actualErrors = null;
try
{
DoStuffAsync().Wait();
Assert.Fail("DoStuffAsync should throw exception");
}
catch(AggregateException exception)
{
actualErrors = exception.InnerExceptions.Select(ex => ex.Message);
}
actualErrors.Should().BeEquivalentTo(expected);
Test will fail if you not awaiting all tasks.
public async Task DoStuffAsync()
{
var tasks = { dependency.FooAsync(), dependency.BarAsync() };
reutrn Task.WhenAll(tasks.Skip(1));
// Test fail with message:
// Expected subject to be a collection with 2 item(s), but {"Bar"}
// contains 1 item(s) less than {"Foo", "Bar"}.
}
Upvotes: 2