Faking a long running asynchronous call

A few days ago I needed to make sure that a specific method would only get called once no matter how many times it’s caller is invoked. The simplified code looked something like this:

public async Task CallLongOperation()
{
var result = await _client.LongWebCall();

if (result.Failed)
{
// log failure and exit
}
}

I needed to make sure that the client was invoked just once no matter how many times CallLongOperation gets called – and to make things interesting the client’s method is asynchronous. Usually when I want to fake a long running call I use WaitHandle but in this case I had something even better…

During previous work I’ve used TaskCompletionSource in order to enable async calls where needed and it seemed only logical that the same method would work for my unit tests:

[TestMethod]
public void CallLongOperation_DuringOperationCallAgain_CalledOnlyOnce()
{
var fakeClient = A.Fake();

var completionSource = new TaskCompletionSource();
A.CallTo(() => fakeClient.LongWebCall()).Returns(completionSource.Task);

var cut = new ClassUnderTest(fakeClient);

cut.CallLongOperation();
cut.CallLongOperation();

completionSource.SetResult(new Result());
A.CallTo(() => fakeClient.LongWebCall()).MustHaveHappened(Repeated.Exactly.Once);
}

Using the TaskCompletionSource (line 6) help me simulate an async call that won’t return until I call SetResult on it (line 14) and since I do not muse await on the actual call I write the whole test without creating any additional threads – creating a simple and deterministic unit test.
It amazed me on how simple it become testing methods that uses async/await – just because the code uses asynchronous calls does not mean that its unit tests need to be complicated or unpredictable.

Happy coding…

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s