Verify that task is being awaited - c#

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);

Related

Should I be using await inside my Task.Run()?

** I've summarised this question at the bottom with an edit **
This has been asked before but I think my circumstances are different.
I am processing multiple requests simultaneously.
This is my code to do that, it runs in a loop. I've removed a bit of code that handles the taskAllocated variable for brevity.
while (!taskAllocated)
{
lock (_lock)
{
// Find an empty slot in the task queue to insert this task
for (i = 0; i < MaxNumTasks; i++)
{
if (_taskQueue[i] == null)
{
_taskQueue[i] = Task.Run(() => Process());
_taskQueue[i].ContinueWith(ProcessCompleted);
break;
}
}
}
}
Process is a typical async Task Process() { CpuIntensiveStuff(); } method.
I've been running the above code, and it has been working fine. It multithreads nicely. Whenever an item comes in, it will find an empty slot in the task queue, and kick it off. When the task completes, the ProcessCompleted method runs, and frees up the slot.
But then I thought, shouldn't I be using await inside my Task.Run? Something like:
_taskQueue[i] = Task.Run(async () => await Process());
After thinking about it, I'm not sure. ContinueWith triggers correctly, when the task has completed, so perhaps it's not necessary.
I ask because I wanted to monitor and log how long each task takes to complete.
So Instead of Process(), I would make another method like:
async Task DoProcess()
{
var sw = Stopwatch.StartNew();
Process();
sw.Stop();
Log(sw.ElapsedMilliseconds);
}
And it occurred to me that if I did that, I wasn't sure if I'd need to await Process(); or not, in addition to not knowing if I should await inside the Task.Run()
I'm in a bit of a tizz about this. Can anyone offer guidance?
Edit:
To summarise:
If Somemethod is:
void SomeMethod() { }
Then
Task.Run(() => SomeMethod()); is great, calls SomeMethod on a new 'thread' (not technically, but you know what I mean).
However, my SomeMethod is actually:
async Task SomeMethod() { }
Do you need to do anything special with Task.Run()?
My code, I am not, I am just straight up ignoring that it's an async Task, and that seems to work:
Task.Run(() => SomeMethod()); // SomeMethod is async Task but I am ignoring that
But I'm not convinced that it a) should work or b) is a good idea. The alternative could be to do:
Task.Run(async() => await SomeMethod());
But is there any point? And this is compounded by the fact I want to really do:
Task.Run(() =>
{
someCode();
var x = startTimer();
SomeMethod();
var y = stopTimer();
someMoreCode()
});
but without await I'm not sure it will wait for somemethod to finish and the timer will be wrong.
Things become more clear if you do not use anonymous methods. For example,
Task.Run(() => Process())
is equivalent to this:
Task.Run(DoSomething);
Task DoSomething() {
return Process();
}
Whereas
Task.Run(async () => await Process())
is equivalent to this:
Task.Run(DoSomething);
async Task DoSomething() {
await Process();
}
In most cases, there is no functional difference between return SomethingThatReturnsATask() and return await SomethingThatReturnsATask(), and you usually want to return the Task directly and not use await (for reasons described here). When used inside Task.Run, things could easily go bad if the .NET team didn't have your back.
It is important to note that asynchronous methods start running on the same thread just like any other method. The magic happens at the first await that acts on an incomplete Task. At that point, await returns its own incomplete Task. That's important - it returns, with a promise to do the rest later.
This could have meant that the Task returned from Task.Run would complete whenever Process() returns a Task. And since Process() returns a Task at the first await, that would happen when it has not yet totally completed.
The .NET team has your back
That is not the case however, because Task.Run has a specific overload for when you give it a method returning a Task. And if you look at the code, it returns a Task *that is tied to the Task you return.
That means that the Task returned from Task.Run(() => Process()) will not complete until the Task returned from Process() has completed.
So your code is fine the way it is.

Lack of await warning in async method that has await in a lambda

Either Visual Studio is confused, or I am (probably me).
If I have
public async Task<Response> DoSomething()
{
//stuff
listOfStuff.ForEach(async s => await _repo.DoThing(s));
return new Response(listOfStuff.Count);
}
It complains that
This async method lacks 'await' ...
However if I change my method to
public async Task<Response> DoSomething()
{
//stuff
foreach (var s in listOfStuff)
{
await _repo.DoThing(s);
}
return new Response(listOfStuff.Count);
}
Then it is perfectly happy and the warning goes away.
So twofold question, is the warning correct and if it is, what is the reasoning for the difference? I'm under the impression that the two methods are intrinsically the same, if the warning is correct, then I must assume that my impression is wrong.
In the first version, the DoSomething function lacks an await operator. The only await is within the async void lambda passed to the ForEach method. In the second version the DoSomething function has an await as part of the actual body of the function and thus you get no warning. It doesn't matter if the listOfStuff may or may not be empty, the condition that the method needs an await is satisfied.
Now the functional difference may not be immediatly clear but it is critical. As stated the first version uses an async void method. That is un-awaitable and the method will therefore continue before the async operation completes as you can see with this test:
[Test]
public void DoSomething()
{
var sw = Stopwatch.StartNew();
var list = Enumerable.Range(0, 10).ToList();
list.ForEach(async x => await Task.Delay(TimeSpan.FromSeconds(1)));
Console.WriteLine($"{sw.ElapsedMilliseconds}ms");
}
Result 6ms, not the 10 seconds we'd expect. The second version of your code is a properly awaitable async Task:
[Test]
public async Task DoSomething()
{
var sw = Stopwatch.StartNew();
var list = Enumerable.Range(0, 10).ToList();
foreach(var x in list)
{
await Task.Delay(TimeSpan.FromSeconds(1));
}
Console.WriteLine($"{sw.ElapsedMilliseconds}ms");
}
And we see the result is: 10032ms right within expectations.
If we replace the lambda with a local function, things may become clearer:
public async Task<Response> DoSomething()
{
//stuff
listOfStuff.ForEach(ProcessStuffAsync);
return new Response(listOfStuff.Count);
async Task ProcessStuffAsync(Stuff s) // local function
{
await _repo.DoThing(s);
}
}
The DoSomething method returns a Task, but it is not really asynchronous because it lacks an await. So the Task returned will be in a completed state. All code inside DoSomething (excluding the code inside the local function) will run synchronously.
The local function ProcessStuffAsync is trully asynchronous, and will return one Task each time is called. These tasks are neither awaited nor stored somewhere inside the DoSomething method, so they are fire-and-forget tasks. Nobody knows what's gonna happen to them.
Update: The code above doesn't compile because List.ForEach cannot accept the ProcessStuffAsync local function as argument. The compiler complains that it has wrong return type. To make the code compile, the local function must return void. But async void functions are a can of worms by themselves.

Multiple hierarchy of task

I want to call a task which itself call a async method which inturn returna bool value.
I want to do something on the basis of that outcome.
I can get the data on outcome.Result.Result but this does not look good and I wish to have the output in outcome.Result.
I can not figure it out.
Can someone please guide.
private void OnValidated(ValidatedIntergrationEvent evt)
{
var outcome=Task.Factory.StartNew(() => mydata.UpdateValidated());
if (outcome.Result.Result)//This work fine but I think I need something to do so that outcome.Result gives my solution.
{ }
else { }
}
public async Task<bool> UpdateValidated()
{
var result= await Mediator.Send(new ValidatedEvent(this));
return result;
}
public async Task<bool> Handle(ValidatedEvent notification, CancellationToken cancellationToken)
{ //dO WORK
// return Task.FromResult(true);
return true;
}
Since UpdateValidated is already asynchronous, you should just call it directly to execute it. Things like Task.Factory.StartNew or Task.Run offer a way to put synchronous tasks on a new thread so that they can run asynchronously. So you should just call it directly:
private void OnValidated(ValidatedIntergrationEvent evt)
{
var outcome = mydata.UpdateValidated()
// Note: this WILL block, regardless of how you call the async function
var result = outcome.Result;
}
You should try to avoid using .Result though, as this will block synchronous functions until the asynchronous result is ready, and may even cause deadlocks. If the OnValidated is a standard event handler, you could make it asynchronous instead and await your task:
private async void OnValidated(ValidatedIntergrationEvent evt)
{
var result = await mydata.UpdateValidated()
}
But this make this event handler fire and forget which can be dangerous. So you should really try to change your code that you are truly running asynchronously when calling asynchronous code.
Finally, note that you can force the asynchronous task onto a separate thread using Task.Run. This is useful when the asynchronous call also does a lot on the CPU:
var outcome = Task.Run(() => mydata.UpdateValidated());
This looks very similar to your Task.Factory.StartNew() call but returns only a Task<bool> instead of your Task<Task<bool>>. This is because Task.Run has an overload that explicitly allows you to call asynchronous methods which makes Task.Run just pass on the result.

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.

await AsyncMethod() versus await await Task.Factory.StartNew<TResult>(AsyncMethod)

Given the following method:
public async Task<MyObject> DoSomethingAsync() {
// do some work
await OpenSomeFileAsync();
return new MyObject();
}
Is there a difference between:
public async void SomeEventHandler(EventArgs args) {
var myObject = await await Task.Factory.StartNew<Task<MyObject>>( DoSomethingAsync);
// do something with myObject
}
and:
public async void SomeEventHandler(EventArgs args) {
var myObject = await DoSomethingAsync();
// do something with myObject
}
I was thinking that the "do some work" part of DoSomethingAsync would happen immediately in a new task in the first case, but to be honest I don't really understand fully how Tasks, async and await are working, and I'm pretty sure I'm just overcomplicating things for myself.
EDIT:
This question came about from looking at this Metro example:
http://code.msdn.microsoft.com/windowsapps/Sharing-Content-Target-App-e2689782
Specifically in MainPage.xaml.cs, they have this:
var unused = Task.Factory.StartNew(async () => { // some work... });
// unused is of type Task<TResult>
I was trying to rework it without using an anonymous async function and I started wondering, why not just write an async method and await it, instead of calling StartNew and handing in an async function?
Most of the time, adding another Task is not useful, but in some cases, it can be.
The difference is if you're on the UI thread (or something similar) and execute DoSomethingAsync() directly, its first part (// do some work) will also execute on the UI thread, and so will any continuation parts of the method (unless they use ConfigureAwait()). On the other hand, if you start another Task, both the first part and any following parts of DoSomethingAsync() will execute on the ThreadPool.
If DoSomethingAsync() is written correctly, adding another Task shouldn't give you any advantages (and will give you the disadvantage of more overhead), but I can imagine there are cases where it will make a difference.
Also, instead of using Task.Factory.StartNew() and two awaits, you could write:
await Task.Run(DoSomethingAsync);
Yes, there is a difference: in the first form, you have an extra level of Task, which brings absolutely nothing useful.
The first form is basically equivalent to this:
Task<Task<MyObject>> task1 = Task.Factory.StartNew<Task<MyObject>>( DoSomethingAsync);
Task<MyObject>> task2 = await task1;
var myObject = await task2;
So it doesn't really make sense: you're creating a task that just... creates another task.

Categories