Unexpected behavior when passing async Actions around - c#

I'm pretty familiar with the async/await pattern, but I'm bumping into some behavior that strikes me as odd. I'm sure there's a perfectly valid reason why it's happening, and I'd love to understand the behavior.
The background here is that I'm developing a Windows Store app, and since I'm a cautious, conscientious developer, I'm unit testing everything. I discovered pretty quickly that the ExpectedExceptionAttribute doesn't exist for WSAs. Weird, right? Well, no problem! I can more-or-less replicate the behavior with an extension method! So I wrote this:
public static class TestHelpers
{
// There's no ExpectedExceptionAttribute for Windows Store apps! Why must Microsoft make my life so hard?!
public static void AssertThrowsExpectedException<T>(this Action a) where T : Exception
{
try
{
a();
}
catch (T)
{
return;
}
Assert.Fail("The expected exception was not thrown");
}
}
And lo, it works beautifully.
So I continued happily writing my unit tests, until I hit an async method that I wanted to confirm throws an exception under certain circumstances. "No problem," I thought to myself, "I can just pass in an async lambda!"
So I wrote this test method:
[TestMethod]
public async Task Network_Interface_Being_Unavailable_Throws_Exception()
{
var webManager = new FakeWebManager
{
IsNetworkAvailable = false
};
var am = new AuthenticationManager(webManager);
Action authenticate = async () => await am.Authenticate("foo", "bar");
authenticate.AssertThrowsExpectedException<LoginFailedException>();
}
This, surprisingly, throws a runtime error. It actually crashes the test-runner!
I made an overload of my AssertThrowsExpectedException method:
public static async Task AssertThrowsExpectedException<TException>(this Func<Task> a) where TException : Exception
{
try
{
await a();
}
catch (TException)
{
return;
}
Assert.Fail("The expected exception was not thrown");
}
and I tweaked my test:
[TestMethod]
public async Task Network_Interface_Being_Unavailable_Throws_Exception()
{
var webManager = new FakeWebManager
{
IsNetworkAvailable = false
};
var am = new AuthenticationManager(webManager);
Func<Task> authenticate = async () => await am.Authenticate("foo", "bar");
await authenticate.AssertThrowsExpectedException<LoginFailedException>();
}
I'm fine with my solution, I'm just wondering exactly why everything goes pear-shaped when I try to invoke the async Action. I'm guessing because, as far as the runtime is concerned, it's not an Action, I'm just cramming the lambda into it. I know the lambda will happily be assigned to either Action or Func<Task>.

It is not surprising that it may crash the tester, in your second code fragment scenario:
Action authenticate = async () => await am.Authenticate("foo", "bar");
authenticate.AssertThrowsExpectedException<LoginFailedException>();
It's actually a fire-and-forget invocation of an async void method, when you call the action:
try
{
a();
}
The a() returns instantly, and so does the AssertThrowsExpectedException method. At the same time, some activity started inside am.Authenticate may continue executing in the background, possibly on a pool thread. What's exactly going on there depends on the implementation of am.Authenticate, but it may crash your tester later, when such async operation is completed and it throws LoginFailedException. I'm not sure what is the synchronization context of the unit test execution environment, but if it uses the default SynchronizationContext, the exception may indeed be thrown unobserved on a different thread in this case.
VS2012 automatically supports asynchronous unit tests, as long as the test method signatures are async Task. So, I think you've answered your own question by using await and Func<T> for your test.

Related

Async method that returns result and Task

I'm trying to design a public method that returns a quick result and, if needed, kicks off a long-running background task.
The result is retrieved within the method pretty quickly, and once it is retrieved it needs to be immediately available to the caller, without waiting for the potential background task to complete.
The background task is either not needed at all, or it must run for a significant amount of time - longer than the caller and all other logic in the program would take to complete without it.
Looking through the MS docs, the best design option I can come up with is to return two things from this method: the result, as well as a Task for the background task.
I don't see a better way to do this, but there are some downsides: first, the responsibility for making sure the background task completes falls on the caller of the method, even though the caller really just wants to consume the immediate result and not be concerned with the behind-the-scene stuff. Second, it is awkward to return null if the background task isn't needed to begin with: now the caller must ensure the task isn't null, in addition to making sure it completes if it is null.
What other options are available for this sort of situation?
Here's an example of what my current design looks like:
public async Task<Tuple<string, Task>> GetAndSave() {
var networkResult = await GetFromNetworkAsync();
if (NeedsToSave(networkResult)) {
var saveTask = SaveToDiskAsync(networkResult);
return new Tuple<string, Task>(networkResult, saveTask);
}
else {
return new Tuple<string, Task>(networkResult, null);
}
}
first, the responsibility for making sure the background task completes falls on the caller of the method, even though the caller really just wants to consume the immediate result and not be concerned with the behind-the-scene stuff.
If it's important to make sure the background task completes then instead of returning the Task you could hand it off to another object (that has been injected into the class that has your GetAndSave method). For example:
public class Foo
{
readonly Action<Task> _ensureCompletion;
public Foo(Action<Task> ensureCompletion)
{
_ensureCompletion = ensureCompletion;
}
public async Task<string> GetAndSaveAsync() // Your method
{
string networkResult = await GetFromNetworkAsync();
if (NeedsToSave(networkResult))
{
Task saveTask = SaveToDiskAsync(networkResult);
_ensureCompletion(saveTask); // This is a synchronous call... no await keyword here. And it returns `void`
}
return networkResult;
}
Task<string> GetFromNetworkAsync() {...}
bool NeedsToSave(string x) {...}
Task SaveToDiskAsync(string x) {...}
}
Now you can inject whatever follow-up behavior you desire for the saveTask. For example, you could write stuff out to the console depending on how it goes:
async Task DoStuff()
{
var foo = new Foo(async task =>
// ^^^^^ More on this in a moment
{
try
{
await task;
Console.Writeline("It worked!");
}
catch (Exception e)
{
Console.Writeline(e.ToString());
}
});
var immediateResult = await foo.GetAndSaveAsync();
// do stuff with `immediateResult`
}
Now, the thing that might be confusing about this (and the power behind this type of solution) is how you can have a synchronous call on the one hand:
_ensureCompletion(saveTask); // This is a synchronous call... no await keyword here
...that does asynchronous things:
var foo = new Foo(async task => ...);
// ^^^^^ This statement lambda is asynchronous
(The injected delegate might even write out to the console on a different thread than whatever thread called GetAndSaveAsync()!)
There's no magic here. It all comes down to SynchronizationContext and the inner workings of async/await.
When the compiler encounters the await keyword (in an async context) then it will do a few things:
Turn everything after the await into a continuation (basically a delegate with some state)
Replace the await keyword with something like SynchronizationContext.Current.Post(continuation)
In other words, this:
async void EnsureCompletion(Task task)
{
try
{
await task;
Console.Writeline("It worked!");
}
catch (Exception e)
{
Console.Writeline(e.ToString());
}
}
...gets turned into something like this:
void EnsureCompletion(Task task)
{
try
{
task.ContinueWith(t => SynchronizationContext.Current.Post(_ =>
{
if (t.IsCompletedSuccessfully)
{
Console.Writeline("It worked!");
}
else
{
Console.Writeline(task.Exception.ToString());
}
});
}
catch (Exception e)
{
Console.Writeline(e.ToString());
}
}
As you can see, EnsureCompletion is an entirely synchronous function that does (almost) the exact same thing as its asynchronous form. Notice how it returns void and everything. This is how you can jam an asynchronous statement lambda into a delegate parameter that has a synchronous signature.
I hinted that the console writing might happen on a totally different thread. That's because async/await is orthogonal to threading. It depends on whatever the currently assigned implementation of SynchronizationContext is programmed to do. Unless you're using WPF or WinForms then by default there will be no SynchronizationContext and continuations (the things that get passed to SynchronizationContext.Post) will just be tossed over to whatever thread happens to be free in the default thread pool.
Second, it is awkward to return null if the background task isn't needed to begin with: now the caller must ensure the task isn't null, in addition to making sure it completes if it is null.
I'm of the opinion that null was a design mistake in C#. (Ask me what some other ones are :) ). If you return null from this method:
public Task DoSomethingAsync()
{
return null; // Compiles just fine
}
...then anyone who uses it will encounter a NullReferenceException when they await it.
async Task Blah()
{
await DoSomethingAsync(); // Wham! NullReferenceException :(
}
(the reason why comes back to how the compiler desugurs the await keyword)
...and it's awkward to have to check for nulls everywhere.
Much better would be to just return Task.CompletedTask as #juharr said.
But if you just hand off the background task like I showed above then you don't have to worry about this.

Why won't this async/await run asynchronously?

I've searched for the answer to this but according to many guides and SO questions this code still appears correct to me, yet it runs synchronously.
private void CheckConditions()
{
foreach (var obj in myObjects)
{
if (obj.ConditionMet)
{
HandleConditionAsync(obj);
}
}
DoOtherWork();
}
private async void HandleConditionAsync(MyObject obj)
{
// shouldn't control transfer back to CheckConditions() here while we wait for user input?
string userInput = await obj.MessagePromptAsync("hello user");
DoSomeBookkeeping(obj);
}
// (MyObject.cs)
private MessagePrompt messagePrompt; // inherits from UserControl
public async Task<string> MessagePromptAsync(string prompt)
{
return await Task.FromResult<string>(messagePrompt.Prompt(prompt));
}
// (MessagePrompt.cs)
public string Prompt(string prompt)
{
this.UIThread(() => this.SetMessagePrompt(prompt));
userInputAutoResetEvent.WaitOne();
return myResult; // set in a button handler that also sets the AutoResetEvent
}
I'm intending for CheckConditions() to continue along merrily but instead it is stuck on MessagePrompt's AutoResetEvent despite my async/awaits. The only thing I can figure might be wrong is that perhaps MessagePrompt's methods aren't able to run asynchronously due to some restriction from UserControl, its use of a UI thread reference, or maybe non-async methods at the top of the stack.
There's nothing in your code that's asynchronous. The only task you have, you created from a result value, meaning the Prompt() method has to complete and return its result before you'll even get the Task object back to wait on. That object will already be completed, so any await on it will complete immediately, once it has the Task to wait on.
Maybe you meant this instead:
public async Task<string> MessagePromptAsync(string prompt)
{
return await Task.Run(() => messagePrompt.Prompt(prompt));
}
Or alternatively (if you really do have nothing else in the MessagePromptAsync() method):
public Task<string> MessagePromptAsync(string prompt)
{
return Task.Run(() => messagePrompt.Prompt(prompt));
}
Note that this may lead to a different problem, depending on what DoOtherWork() and UIThread() actually do. If your UI thread gets tied up in DoOtherWork() and the UIThread() method is wrapping Dispatcher.Invoke() or similar, then you'll have a deadlock.
If that does not address your problem, please provide a good Minimal, Complete, and Verifiable code example that reliably reproduces the problem.
You need to make CheckConditions() async as well, and then await the call to HandleConditionAsync(MyObject obj). CheckConditions() runs synchronously in your sample.
private async Task CheckConditionsAsync()
{
foreach (var obj in myObjects)
{
if (obj.ConditionMet)
{
await HandleConditionAsync(obj);
}
}
DoOtherWork();
}
Also, and this is just a best practices thing, an async method should always return a Task when possible. The only time I've ever had to use async void is for compatibility with an event handler. You can see I've changed CheckConditions() this way, and HandleConditionAsync(MyObject obj) should be modified similarly. I also changed the method name to represent it's asynchronous behaviour.
If you need to run a method that returns a Task synchronously (and you shouldn't do this, this is an indication of something incorrect about your design), you can run it with Task.FromResult(MyMethodAsync()). Again, avoid doing this wherever you can, it defeats the purpose of making a method asynchronous to in the first place.

Partial code coverage of await [duplicate]

When I analyse code coverage in Visual Studio 2012, any of the await lines in async methods are showing as not covered even though they are obviously executing since my tests are passing. The code coverage report says that the uncovered method is MoveNext, which is not present in my code (perhaps it's compiler-generated).
Is there a way to fix code coverage reporting for async methods?
Note:
I just ran coverage using NCover, and the coverage numbers make a lot more sense using that tool. As a workaround for now, I'll be switching to that.
This can happen most commonly if the operation you're awaiting is completed before it's awaited.
I recommend you test at least synchronous and asynchronous success situations, but it's also a good idea to test synchronous and asynchronous errors and cancellations.
The reason the code is not shown as being covered has to do with how async methods are implemented. The C# compiler actually translates the code in async methods into a class that implements a state machine, and transforms the original method into a stub that initialized and invokes that state machine. Since this code is generated in your assembly, it is included in the code coverage analysis.
If you use a task that is not complete at the time the code being covered is executing, the compiler-generated state machine hooks up a completion callback to resume when the task completes. This more completely exercises the state machine code, and results in complete code coverage (at least for statement-level code coverage tools).
A common way to get a task that is not complete at the moment, but will complete at some point is to use Task.Delay in your unit test. However, that is generally a poor option because the time delay is either too small (and results in unpredictable code coverage because sometimes the task is complete before the code being tests runs) or too large (unnecessarily slowing the tests down).
A better option is to use "await Task.Yield()". This will return immediately but invoke the continuation as soon as it is set.
Another option - though somewhat absurd - is to implement your own awaitable pattern that has the semantics of reporting incomplete until a continuation callback is hooked up, and then to immediately complete. This basically forces the state machine into the async path, providing the complete coverage.
To be sure, this is not a perfect solution. The most unfortunate aspect is that it requires modification to production code to address a limitation of a tool. I would much prefer that the code coverage tool ignore the portions of the async state machine that are generated by the compiler. But until that happens, there aren’t many options if you really want to try to get complete code coverage.
A more complete explanation of this hack can be found here: http://blogs.msdn.com/b/dwayneneed/archive/2014/11/17/code-coverage-with-async-await.aspx
There are situations where I don't care about testing the async nature of a method but just want to get rid of the partial code coverage. I use below extension method to avoid this and it works just fine for me.
Warning "Thread.Sleep" used here!
public static IReturnsResult<TClass> ReturnsAsyncDelayed<TClass, TResponse>(this ISetup<TClass, Task<TResponse>> setup, TResponse value) where TClass : class
{
var completionSource = new TaskCompletionSource<TResponse>();
Task.Run(() => { Thread.Sleep(200); completionSource.SetResult(value); });
return setup.Returns(completionSource.Task);
}
and the usage is similar to the Moq's ReturnsAsync Setup.
_sampleMock.Setup(s => s.SampleMethodAsync()).ReturnsAsyncDelayed(response);
I created a test runner that runs a block of code multiple times and varies the task that is delayed using a factory. This is great for testing the different paths through simple blocks of code. For more complex paths you may want to create a test per path.
[TestMethod]
public async Task ShouldTestAsync()
{
await AsyncTestRunner.RunTest(async taskFactory =>
{
this.apiRestClient.GetAsync<List<Item1>>(NullString).ReturnsForAnyArgs(taskFactory.Result(new List<Item1>()));
this.apiRestClient.GetAsync<List<Item2>>(NullString).ReturnsForAnyArgs(taskFactory.Result(new List<Item2>()));
var items = await this.apiController.GetAsync();
this.apiRestClient.Received().GetAsync<List<Item1>>(Url1).IgnoreAwait();
this.apiRestClient.Received().GetAsync<List<Item2>>(Url2).IgnoreAwait();
Assert.AreEqual(0, items.Count(), "Zero items should be returned.");
});
}
public static class AsyncTestRunner
{
public static async Task RunTest(Func<ITestTaskFactory, Task> test)
{
var testTaskFactory = new TestTaskFactory();
while (testTaskFactory.NextTestRun())
{
await test(testTaskFactory);
}
}
}
public class TestTaskFactory : ITestTaskFactory
{
public TestTaskFactory()
{
this.firstRun = true;
this.totalTasks = 0;
this.currentTestRun = -1; // Start at -1 so it will go to 0 for first run.
this.currentTaskNumber = 0;
}
public bool NextTestRun()
{
// Use final task number as total tasks.
this.totalTasks = this.currentTaskNumber;
// Always return has next as turn for for first run, and when we have not yet delayed all tasks.
// We need one more test run that tasks for if they all run sync.
var hasNext = this.firstRun || this.currentTestRun <= this.totalTasks;
// Go to next run so we know what task should be delayed,
// and then reset the current task number so we start over.
this.currentTestRun++;
this.currentTaskNumber = 0;
this.firstRun = false;
return hasNext;
}
public async Task<T> Result<T>(T value, int delayInMilliseconds = DefaultDelay)
{
if (this.TaskShouldBeDelayed())
{
await Task.Delay(delayInMilliseconds);
}
return value;
}
private bool TaskShouldBeDelayed()
{
var result = this.currentTaskNumber == this.currentTestRun - 1;
this.currentTaskNumber++;
return result;
}
public async Task VoidResult(int delayInMilliseconds = DefaultDelay)
{
// If the task number we are on matches the test run,
// make it delayed so we can cycle through them.
// Otherwise this task will be complete when it is reached.
if (this.TaskShouldBeDelayed())
{
await Task.Delay(delayInMilliseconds);
}
}
public async Task<T> FromResult<T>(T value, int delayInMilliseconds = DefaultDelay)
{
if (this.TaskShouldBeDelayed())
{
await Task.Delay(delayInMilliseconds);
}
return value;
}
}

How to use a breakpoint after await in unit test?

I am surprised my breakpoint after awaiting an async method that is on a line that references the awaited Task<T> is never hit:
[Test]
public async void GetSomethingTest()
{
var service = SimpleIoc.Default.GetInstance<IService>();
var result = await service.TryGetSomethingAsync(20);
Assert.IsTrue(result.IsSuccess);
Assert.IsNotNull(result.ReturnValue);
}
Putting a breakpoint on the first Assert line is never hit but the test passes.
How to I break when await returns?
UPDATE: I guess it is because the test framework is not awaiting the invocation of the test method, I am using NUnit 2.6.3 and that claims async support, however whether that entails breaking after an await like I am trying to do, I am not sure...
The problem is that your method is async void. That has fire-and-forget semantics.
Conceptually what your method is doing with the async-await usage looks like this:
[Test]
public void GetSomethingTest()
{
var service = SimpleIoc.Default.GetInstance<IService>();
service.TryGetSomethingAsync(20).ContinueWith(t =>
{
var result = t.Result;
Assert.IsTrue(result.IsSuccess);
Assert.IsNotNull(result.ReturnValue);
});
}
Now it should be clear what the problem is. Your test method immediately returns as soon as TryGetSomethingAsync returns its Task. So the test immediately finishes. Since no exceptions were thrown, it is a success.
If your test framework supports Task-returning tests, you can fix your test to do what you want by simply changing its return type to Task instead of void.
[Test]
public async Task GetSomethingTest()
{
var service = SimpleIoc.Default.GetInstance<IService>();
var result = await service.TryGetSomethingAsync(20);
Assert.IsTrue(result.IsSuccess);
Assert.IsNotNull(result.ReturnValue);
}
This will conceptually translate to the following.
[Test]
public Task GetSomethingTest()
{
var service = SimpleIoc.Default.GetInstance<IService>();
return service.TryGetSomethingAsync(20).ContinueWith(t =>
{
var result = t.Result;
Assert.IsTrue(result.IsSuccess);
Assert.IsNotNull(result.ReturnValue);
});
}
Notice how the Task continuation is returned, so that the test framework can now wait on it, ensuring that all the test's code has time to run before the test is considered finished.
(Technically a framework could be made to work in the async void case as well, but I don't know of any reason why that would be a good feature, so I expect most don't handle it.)
If your test framework does not support Task-returning tests, you can fix your test by using .Result instead of await.
[Test]
public void GetSomethingTest()
{
var service = SimpleIoc.Default.GetInstance<IService>();
var result = service.TryGetSomethingAsync(20).Result;
Assert.IsTrue(result.IsSuccess);
Assert.IsNotNull(result.ReturnValue);
}
This will simply block the current thread until the Task returned by TryGetSomethingAsync is completed.

Can NUnit expect a timeout?

I would like to test a method that I am expecting to block in a specific situation.
I tried a combination of the TimeoutAttribute and ExpectedExceptionAttribute:
[Test]
[Timeout(50), ExpectedException(typeof(ThreadAbortException))]
public void BlockingCallShouldBlock()
{
this.SomeBlockingCall();
}
Unfortunately this does not work as the ThreadAbortException I was reading about here seems to get caught by NUnit itself.
Is there a way to expect timeouts (with NUnit)?
For a problem like this, I would probably use Task and Task.Wait(int) or Task.Wait(TimeSpan). For example:
[Test]
public void BlockingCallShouldBlock()
{
var task = Task.Run(() => SomeBlockingCall());
var completedInTime = task.Wait(50); // Also an overload available for TimeSpan
Expect(completedInTime, Is.False);
}
Be warned however, this will invoke SomeBlockingCall on a background thread, but for the majority of unit tests, this is a non-issue.

Categories

Resources