How can I unit test that an async Task was awaited? - c#

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.

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"}.
}

Related

Test a function throwing an Exception in a Task in xunit

I want to test using xunit a function that run a task and throw in a that task
For example :
public void doSomething(){
Task.Run(() =>
{
throw new ArgumentNullException();
});
}
When I want to test this function by doing this :
[Fact]
public void TestIfTheMethodThrow()
{
Assert.Throws<ArgumentNullException>(() => doSomething()); // should return true but return false
}
I want that the Task.Run() finish completely then the assert can be done. anyone have a solution ?
Raising and handling exceptions using TPL (the Tasks library) is slightly different, than the "standard" exception handling.
It is meaningful to evaluate only a completed task, so you need to wait for the completion, even if in this case it is an exception.
Have a look at this MSDN article Exception handling (Task Parallel Library).
You have two different options:
add .Wait() to the Task.Run(...)`
Task.Run(() =>
{
throw new ArgumentNullException();
}).Wait();
or wait while the task is completed while(!task.IsCompleted) {}
var task = Task.Run(() =>
{
throw new ArgumentNullException();
});
while(!task.IsCompleted) {}
The test result should be then as expected - an exception is thrown.
It could be, that before the Wait your test has passed sporadically - don't be irritated - in this case the task execution was faster than the test check - this is a dangerous source of subtle errors.
You can write your method using async and await
Read this for reference Asynchronous programming with async and await
The new method look like this, and the caller will decide if want wait or not, if you call with await it will wait the task complete, otherwise it will continue without wait the task completion
public async Task DoSomethingAsync()
{
if (true)
throw new ArgumentNullException();
await FooAsync();
}
In the test:
[Fact]
public async Task TestIfTheMethodThrow()
{
await Assert.ThrowsAsync<ArgumentNullException>(() => DoSomethingAsync());
}

How to properly execute a List of Tasks async in C#

I have a list of objects that I need to run a long running process on and I would like to kick them off asynchronously, then when they are all finished return them as a list to the calling method. I've been trying different methods that I have found, however it appears that the processes are still running synchronously in the order that they are in the list. So I am sure that I am missing something in the process of how to execute a list of tasks.
Here is my code:
public async Task<List<ShipmentOverview>> GetShipmentByStatus(ShipmentFilterModel filter)
{
if (string.IsNullOrEmpty(filter.Status))
{
throw new InvalidShipmentStatusException(filter.Status);
}
var lookups = GetLookups(false, Brownells.ConsolidatedShipping.Constants.ShipmentStatusType);
var lookup = lookups.SingleOrDefault(sd => sd.Name.ToLower() == filter.Status.ToLower());
if (lookup != null)
{
filter.StatusId = lookup.Id;
var shipments = Shipments.GetShipments(filter);
var tasks = shipments.Select(async model => await GetOverview(model)).ToList();
ShipmentOverview[] finishedTask = await Task.WhenAll(tasks);
return finishedTask.ToList();
}
else
{
throw new InvalidShipmentStatusException(filter.Status);
}
}
private async Task<ShipmentOverview> GetOverview(ShipmentModel model)
{
String version;
var user = AuthContext.GetUserSecurityModel(Identity.Token, out version) as UserSecurityModel;
var profile = AuthContext.GetProfileSecurityModel(user.Profiles.First());
var overview = new ShipmentOverview
{
Id = model.Id,
CanView = true,
CanClose = profile.HasFeatureAction("Shipments", "Close", "POST"),
CanClear = profile.HasFeatureAction("Shipments", "Clear", "POST"),
CanEdit = profile.HasFeatureAction("Shipments", "Get", "PUT"),
ShipmentNumber = model.ShipmentNumber.ToString(),
ShipmentName = model.Name,
};
var parcels = Shipments.GetParcelsInShipment(model.Id);
overview.NumberParcels = parcels.Count;
var orders = parcels.Select(s => WareHouseClient.GetOrderNumberFromParcelId(s.ParcelNumber)).ToList();
overview.NumberOrders = orders.Distinct().Count();
//check validations
var vals = Shipments.GetShipmentValidations(model.Id);
if (model.ValidationTypeId == Constants.OrderValidationType)
{
if (vals.Count > 0)
{
overview.NumberOrdersTotal = vals.Count();
overview.NumberParcelsTotal = vals.Sum(s => WareHouseClient.GetParcelsPerOrder(s.ValidateReference));
}
}
return overview;
}
It looks like you're using asynchronous methods while you really want threads.
Asynchronous methods yield control back to the calling method when an async method is called, then wait until the methods has completed on the await. You can see how it works here.
Basically, the only usefulness of async/await methods is not to lock the UI, so that it stays responsive.
If you want to fire multiple processings in parallel, you will want to use threads, like such:
using System.Threading.Tasks;
public void MainMethod() {
// Parallel.ForEach will automagically run the "right" number of threads in parallel
Parallel.ForEach(shipments, shipment => ProcessShipment(shipment));
// do something when all shipments have been processed
}
public void ProcessShipment(Shipment shipment) { ... }
Marking the method as async doesn't auto-magically make it execute in parallel. Since you're not using await at all, it will in fact execute completely synchronously as if it wasn't async. You might have read somewhere that async makes functions execute asynchronously, but this simply isn't true - forget it. The only thing it does is build a state machine to handle task continuations for you when you use await and actually build all the code to manage those tasks and their error handling.
If your code is mostly I/O bound, use the asynchronous APIs with await to make sure the methods actually execute in parallel. If they are CPU bound, a Task.Run (or Parallel.ForEach) will work best.
Also, there's no point in doing .Select(async model => await GetOverview(model). It's almost equivalent to .Select(model => GetOverview(model). In any case, since the method actually doesn't return an asynchronous task, it will be executed while doing the Select, long before you get to the Task.WhenAll.
Given this, even the GetShipmentByStatus's async is pretty much useless - you only use await to await the Task.WhenAll, but since all the tasks are already completed by that point, it will simply complete synchronously.
If your tasks are CPU bound and not I/O bound, then here is the pattern I believe you're looking for:
static void Main(string[] args) {
Task firstStepTask = Task.Run(() => firstStep());
Task secondStepTask = Task.Run(() => secondStep());
//...
Task finalStepTask = Task.Factory.ContinueWhenAll(
new Task[] { step1Task, step2Task }, //more if more than two steps...
(previousTasks) => finalStep());
finalStepTask.Wait();
}

Verify that task is being awaited

I have the following code which i'd like to test:
private Task _keepAliveTask; // get's assigned by object initializer
public async Task EndSession()
{
_cancellationTokenSource.Cancel(); // cancels the _keepAliveTask
await _logOutCommand.LogOutIfPossible();
await _keepAliveTask;
}
It is important that the EndSession Task only ends once the `_keepAliveTask' ended. However, I'm struggling to find a way to test it reliably.
Question: How do i unit test the EndSession method and verify that the Task returned by EndSession awaits the _keepAliveTask.
For demonstration purposes, the unit test could look like that:
public async Task EndSession_MustWaitForKeepAliveTaskToEnd()
{
var keepAliveTask = new Mock<Task>();
// for simplicity sake i slightly differ from the other examples
// by passing the task as method parameter
await EndSession(keepAliveTask);
keepAliveTask.VerifyAwaited(); // this is what i want to achieve
}
Further criterias:
- reliable test (always passes when implementation is correct, always fails when implementation is wrong)
- cannot take longer than a few milliseconds (it's a unit test, after all).
I have already taken several alternatives into considerations which i'm documenting below:
non-async method
If there wouldn't be the call to _logOutCommand.LogOutIfPossible() it would be quite simple: i'd just remove the async and return _keepAliveTask instead of awaiting it:
public Task EndSession()
{
_cancellationTokenSource.Cancel();
return _keepAliveTask;
}
The unit test would look (simplified):
public void EndSession_MustWaitForKeepAliveTaskToEnd()
{
var keepAliveTask = new Mock<Task>();
// for simplicity sake i slightly differ from the other examples
// by passing the task as method parameter
Task returnedTask = EndSession(keepAliveTask);
returnedTask.Should().be(keepAliveTask);
}
However, there's two arguments against this:
i have multiple task which need awaiting (i'm considering Task.WhenAll further down)
doing so only moves the responsibility to await the task to the caller of EndSession. Still will have to test it there.
non-async method, sync over async
Of course, I could do something similar:
public Task EndSession()
{
_cancellationTokenSource.Cancel(); // cancels the _keepAliveTask
_logOutCommand.LogOutIfPossible().Wait();
return _keepAliveTask;
}
But that is a no-go (sync over async). Plus it still has the problems of the previous approach.
non-async method using Task.WhenAll(...)
Is a (valid) performance improvement but introduces more complexity:
- difficult to get right without hiding a second exception (when both fail)
- allows parallel execution
Since performance isn't key here i'd like to avoid the extra complexity. Also, previously mentioned issue that it just moves the (verification) problem to the caller of the EndSession method applies here, too.
observing effects instead of verifying calls
Now of course instead of "unit" testing method calls etc. I could always observe effects. Which is: As long as _keepAliveTask hasn't ended the EndSession Task mustn't end either. But since I can't wait indefinite one has to settle for a timeout. The tests should be fast so a timeout like 5 seconds is a no go. So what I've done is:
[Test]
public void EndSession_MustWaitForKeepAliveTaskToEnd()
{
var keepAlive = new TaskCompletionSource<bool>();
_cancelableLoopingTaskFactory
.Setup(x => x.Start(It.IsAny<ICancelableLoopStep>(), It.IsAny<CancellationToken>()))
.Returns(keepAlive.Task);
_testee.StartSendingKeepAlive();
_testee.EndSession()
.Wait(TimeSpan.FromMilliseconds(20))
.Should().BeFalse();
}
But I really really dislike this approach:
hard to understand
unreliable
or - when it's quite reliable - it takes a long time (which unit tests shouldn't).
If all you want is to verify that EndSession is awaiting _keepAliveTask (and you really have full control over _keepAliveTask) then you can create your own awaitable type instead of Task the signals when it's awaited and check that:
public class MyAwaitable
{
public bool IsAwaited;
public MyAwaiter GetAwaiter()
{
return new MyAwaiter(this);
}
}
public class MyAwaiter
{
private readonly MyAwaitable _awaitable;
public MyAwaiter(MyAwaitable awaitable)
{
_awaitable = awaitable;
}
public bool IsCompleted
{
get { return false; }
}
public void GetResult() {}
public void OnCompleted(Action continuation)
{
_awaitable.IsAwaited = true;
}
}
Since all you need to await something is that has a GetAwaiter method that returns something with IsCompleted, OnCompleted and GetResult you can use the dummy awaitable to make sure _keepAliveTask is being awaited:
_keepAliveTask = new MyAwaitable();
EndSession();
_keepAliveTask.IsAwaited.Should().BeTrue();
If you use some mocking framework you can instead make Task's GetAwaiter return our MyAwaiter.
Use TaskCompletionSource and set its result at a known time.
Verify that before setting the result, the await on EndSession hasn't completed.
Verify that after setting the result, the await on EndSession has completed.
A simplified version could look like the following (using nunit):
[Test]
public async Task VerifyTask()
{
var tcs = new TaskCompletionSource<bool>();
var keepAliveTask = tcs.Task;
// verify pre-condition
Assert.IsFalse(keepAliveTask.IsCompleted);
var waitTask = Task.Run(async () => await keepAliveTask);
tcs.SetResult(true);
await waitTask;
// verify keepAliveTask has finished, and as such has been awaited
Assert.IsTrue(keepAliveTask.IsCompleted);
Assert.IsTrue(waitTask.IsCompleted); // not needed, but to make a point
}
You can also add a short delay at the waitTask to ensure any synchronous execution would be faster, something like:
var waitTask = Task.Run(async () =>
{
await Task.Delay(1);
await keepAliveTask;
});
And if you don't trust your unit test framework to deal correctly with async, you can set a completed flag as part of the waitTask, and check for that in the end. Something like:
bool completed = false;
var waitTask = Task.Run(async () =>
{
await Task.Delay(1);
await keepAliveTask;
completed = true;
});
// { .... }
// at the end of the method
Assert.IsTrue(completed);

How can I realize pattern promise/defered?

I want to write a pattern Promise/Deffered.
Perfect variant in end is:
MyObject().CallMethodReturningPromise()
.done( result => {
...something doing;
} )
.fail( error => {
...error handle;
} )
.always( () => {
...some code;
} )
I've found this implementation https://bitbucket.org/mattkotsenas/c-promises/overview and https://gist.github.com/cuppster/3612000. But how can I use it to solve my task???
C# solves this with Tasks
Tasks solve the same problem as promises do in JavaScript - and you can use them similarly. However normally, you shouldn't.
There are several differences:
Tasks have cancellation built in.
Tasks aren't always started, and you can have tasks and start them later.
Promises perform assimilation, you can't have a Promise<Promise<T>> but you can have a task of a task in C# and might need to call .Unwrap on tasks.
There is one canonical implementation of tasks in the TPL (task parallelization library) that ships with C# but many implementations of promises in JavaScript.
Using Tasks
Here's how you'd use them with the async/await syntax - which will be added to JavaScript in ES7 and can be used in ES6 with yield in some libraries.
async Task Foo(){
try{
var res = await myObject.CallMethodReturningTaskOrAsyncMethod();
doSomethingWithResponse(res);
} catch(e){
// handle errors, this will be called if the async task errors
} finally {
// this is your .always
}
}
You can also use .ContinueWith which parallels to .then but it's very uncommon in C# and is generally frowned upon when await can be used. You can learn more about using async/await here.
Deffereds are mapped to TaskCompletionSource instances and Promises are Tasks in C#. Task.WhenAll is used where you'd use $.when or Promise.all.
Where you'd usually write:
a().then(function(res){
return b(res, "foo");
}).then(function(res2){
// do work on res2
});
You'd do the following in C#:
var res = await a();
var res2 = await b(res, "foo");
// do work on res2.
Seems to me, this perfectly fit with tasks:
var deferred = Task
.Factory
.StartNew(() => /* produce some result (promise) */);
// done
deferred
.ContinueWith(d => Console.WriteLine(d.Result), TaskContinuationOptions.OnlyOnRanToCompletion);
// fail
deferred
.ContinueWith(d => Console.WriteLine(d.Exception), TaskContinuationOptions.OnlyOnFaulted);
// always
deferred
.ContinueWith(d => Console.WriteLine("Do something"));
you can use asynchronous with Task, async and await as follows:
pay attention for handling asynchronous you do not need use try catch
public async Task Method()
{
await Task.Run(() =>
{
//operations
Application.Current.Dispatcher.Invoke(() =>
{
//grab the UI Dispatcher if you need
});
}).ContinueWith(task =>
{
if (task.IsCompleted)
{
//operations success
}
else if (task.IsFaulted)
{
//operations failed
}
});
}

async / await - am I correctly running these methods in parallel?

I have an abstract class called VehicleInfoFetcher which returns information asynchronously from a WebClient via this method:
public override async Task<DTOrealtimeinfo> getVehicleInfo(string stopID);
I'd like to combine the results of two separate instances of this class, running each in parallel before combining the results. This is done within a third class, CombinedVehicleInfoFetcher (also itself a subclass of VehicleInfoFetcher)
Here's my code - but I'm not quite convinced that it's running the tasks in parallel; am I doing it right? Could it be optimized?
public class CombinedVehicleInfoFetcher : VehicleInfoFetcher
{
public HashSet<VehicleInfoFetcher> VehicleInfoFetchers { get; set; }
public override async Task<DTOrealtimeinfo> getVehicleInfo(string stopID)
{
// Create a list of parallel tasks to run
var resultTasks = new List<Task<DTOrealtimeinfo>>();
foreach (VehicleInfoFetcher fetcher in VehicleInfoFetchers)
resultTasks.Add(fetcher.getVehicleInfo(stopID, stopID2, timePointLocal));
// run each task
foreach (var task in resultTasks)
await task;
// Wait for all the results to come in
await Task.WhenAll(resultTasks.ToArray());
// combine the results
var allRealtimeResults = new List<DTOrealtimeinfo>( resultTasks.Select(t => t.Result) );
return combineTaskResults(allRealtimeResults);
}
DTOrealtimeinfo combineTaskResults(List<DTOrealtimeinfo> realtimeResults)
{
// ...
return rtInfoOutput;
}
}
Edit
Some very helpful answers, here is a re-written example to aid discussion with usr below:
public override async Task<object> combineResults()
{
// Create a list of parallel tasks to run
var resultTasks= new List<object>();
foreach (AnotherClass cls in this.OtherClasses)
resultTasks.Add(cls.getResults() );
// Point A - have the cls.getResults() methods been called yet?
// Wait for all the results to come in
await Task.WhenAll(resultTasks.ToArray());
// combine the results
return new List<object>( resultTasks.Select(t => t.Result) );
}
}
Almost all tasks start out already started. Probably, whatever fetcher.getVehicleInfo returns is already started. So you can remove:
// run each task
foreach (var task in resultTasks)
await task;
Task.WhenAll is faster and has better error behavior (you want all exceptions to be propagated, not just the first you happen to stumble upon).
Also, await does not start a task. It waits for completion. You have to arrange for the tasks to be started separately, but as I said, almost all tasks are already started when you get them. This is best-practice as well.
To help our discussion in the comments:
Task Test1() { return new Task(() => {}); }
Task Test2() { return Task.Factory.StartNew(() => {}); }
Task Test3() { return new FileStream("").ReadAsync(...); }
Task Test4() { return new TaskCompletionSource<object>().Task; }
Does not "run" when returned from the method. Must be started. Bad practice.
Runs when returned. Does not matter what you do with it, it is already running. Not necessary to add it to a list or store it somewhere.
Already runs like (2).
The notion of running does not make sense here. This task will never complete although it cannot be explicitly started.

Categories