Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I test for ConfigureAwait(false) in a unit test for async methods?

I have some async library methods where it is important the ConfigureAwait(false) be used "all the way down". I'd like to write an NUnit test that verifies that this is so. How can I do that? I imagine that I'd have to somehow hijack the synchronization context with a custom implementation?

like image 961
ChaseMedallion Avatar asked Jan 02 '14 14:01

ChaseMedallion


People also ask

What is ConfigureAwait do in async await?

ConfigureAwait(false) involves a task that's already completed by the time it's awaited (which is actually incredibly common), then the ConfigureAwait(false) will be meaningless, as the thread continues to execute code in the method after this and still in the same context that was there previously.

Which do I use ConfigureAwait True or false?

In this video we answer the ever popular question “Which do I use, ConfigureAwait True or False?”. The direct answer to this question is: – If you are a writing code for the UI, use ConfigureAwait(true).

What does ConfigureAwait false?

ConfigureAwait(false) is about not returning back to the synchronization context when an awaiter completes. It's about performance, not deadlocks.

Is ConfigureAwait false by default?

To improve performance and avoid potential deadlocks, use ConfigureAwait(false) in any non-UI code. The exception here is app-level code, such as Windows Forms, WPF, and ASP.NET. ConfigureAwait(true) corresponds to the default behavior and does nothing meaningful, therefore such calls can be safely omitted.


1 Answers

I don't think this is possible. You could create a custom synchronization context (see striked answer below), but it would only check the first awaited call. If the first awaited call called uses ConfigureAwait(false), the continuation will run on a different thread, which won't have a SynchronizationContext, so it won't be possible to check whether subsequent async calls use ConfigureAwait(false) or not.


Indeed, a custom synchronization context seems to be the only way. Here's a possible implementation:

class TestSynchronizationContext : SynchronizationContext
{
    public bool PostCalled { get; private set; }

    public override void Post(SendOrPostCallback d, object state)
    {
        PostCalled = true;
        base.Post(d, state);
    }

    public void Reset()
    {
        PostCalled = false;
    }
}

You can then write your test like this:

[Test]
public void TestFoo()
{
    var context = new TestSynchronizationContext();
    SynchronizationContext.SetSynchronizationContext(context);
    FooAsync().Wait();
    Assert.IsFalse(context.PostCalled);
}

if PostCalled is true, it means that the SynchronizationContext's Post method was called, which shouldn't happen if ConfigureAwait(false) was used.

like image 106
Thomas Levesque Avatar answered Oct 17 '22 01:10

Thomas Levesque