I just saw a video class from Jon Skeet where he talks about asynchronous methods for testing modules. It was on a paid website, but I found something similar to what it says in my book (just Ctrl + F "15.6. 3. Testing the device asynchronous code").
The full code can be found on his github , but I simplified it for the sake of my question (my code is mainly StockBrokerTest.CalculateNetWorthAsync_AuthenticationFailure_ThrowsDelayed() but with TimeMachine and Advancer inlined operations).
Suppose we have a class for checking failed login (without unit test to simplify the issue):
public static class LoginTest { private static TaskCompletionSource<Guid?> loginPromise = new TaskCompletionSource<Guid?>(); public static void Main() { Console.WriteLine("== START ==");
Where is the implementation of ManuallyPumpedSynchronizationContext :
public sealed class ManuallyPumpedSynchronizationContext : SynchronizationContext { private readonly BlockingCollection<Tuple<SendOrPostCallback, object>> callbacks; public ManuallyPumpedSynchronizationContext() { callbacks = new BlockingCollection<Tuple<SendOrPostCallback, object>>(); } public override void Post(SendOrPostCallback callback, object state) { Console.WriteLine("Post()"); callbacks.Add(Tuple.Create(callback, state)); } public override void Send(SendOrPostCallback d, object state) { throw new NotSupportedException("Synchronous operations not supported on ManuallyPumpedSynchronizationContext"); } public void PumpAll() { Tuple<SendOrPostCallback, object> callback; while(callbacks.TryTake(out callback)) { Console.WriteLine("PumpAll()"); callback.Item1(callback.Item2); } } }
Output:
== START == Before login Before advance After login After advance == END ==
My question is: Why do we need a ManuallyPumpedSynchronizationContext ?
Why is the standard SynchronizationContext not enough? The Post() method is not even called (based on the output). I tried to comment out the lines marked with // Comment this , and the result is the same, and the statements are passed.
If I understand correctly what John Skeet says in the video, the SynchronizationContext.Post() method should be called when we encounter await with an await task. But this is not so. What am I missing?
Additional Information
Through my research, I came across this answer . To try this, I changed the implementation of the Login() method to:
private static Task<Guid?> Login() {
With this modification, the Post() method was actually called. Output:
== START == Before login Post() Before advance PumpAll() Login() After login After advance == END ==
So, using Jon Skeet TaskCompletionSource , was it not creating ManuallyPumpedSynchronizationContext ?
Note. I think the video that I saw was made only around the release date of C # 5.