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…
[TestMethod] public void CallLongOperation_DuringOperationCallAgain_CalledOnlyOnce() { var fakeClient = A.Fake<IClient>(); var completionSource = new TaskCompletionSource<Result>(); 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.
Labels: .NET, async, C#, MSTest, Multi-threading, Unit tests