How to add a synchronous context to an asynchronous testing method

I have Visual Studio 2012 and an asynchronous test that needs a synchronization context.
But the default synchronization context for MSTest is NULL.
I would like to test how it works in a WPF or WinForms-UI thread that has a synchronization context.
What is the best way to add a SynchronizationContext to a test thread?

[TestMethod] public async Task MyTest() { Assert.IsNotNull( SynchronizationContext.Current ); await MyTestAsync(); DoSomethingOnTheSameThread(); } 
+4
source share
3 answers

Using the information of Panagiotis Kanavos and Stephen Cleary, I can write my test methods as follows:

  [TestMethod] public void MyTest() { Helper.RunInWpfSyncContext( async () => { Assert.IsNotNull( SynchronizationContext.Current ); await MyTestAsync(); DoSomethingOnTheSameThread(); }); } 

The internal code now works in the context of WPF synchronization and handles all exceptions used for MSTest. Helper Method from Stephen Toub:

 using System.Windows.Threading; // WPF Dispatcher from assembly 'WindowsBase' public static void RunInWpfSyncContext( Func<Task> function ) { if (function == null) throw new ArgumentNullException("function"); var prevCtx = SynchronizationContext.Current; try { var syncCtx = new DispatcherSynchronizationContext(); SynchronizationContext.SetSynchronizationContext(syncCtx); var task = function(); if (task == null) throw new InvalidOperationException(); var frame = new DispatcherFrame(); var t2 = task.ContinueWith(x=>{frame.Continue = false;}, TaskScheduler.Default); Dispatcher.PushFrame(frame); // execute all tasks until frame.Continue == false task.GetAwaiter().GetResult(); // rethrow exception when task has failed } finally { SynchronizationContext.SetSynchronizationContext(prevCtx); } } 
+6
source

You can create your own SynchronizationContext-derived class and register it as the current context with SynchronizationContext.SetSynchronizationContext . Read Steven Tubโ€™s notes on the โ€œ Waiting, SynchronizationContext and Console Applications โ€ and โ€œ Await, SynchronizationContext and Console: Part 2 โ€ pages .

Your own SynchronizationContext should only override the Post method, which receives callbacks for asynchronous execution. How you do them is up to you.

The first message provides a synchronization context in which all published actions in the queue are stored and a lock cycle that takes actions from the queue and executes them in a single thread.

+6
source

You can use the single-threaded SynchronizationContext in my AsyncEx library called AsyncContext :

 [TestMethod] public void MyTest() { AsyncContext.Run(async () => { Assert.IsNotNull( SynchronizationContext.Current ); await MyTestAsync(); DoSomethingOnTheSameThread(); }); } 

However, this does not completely fake a specific user interface environment, for example, Dispatcher.CurrentDispatcher will still be null . If you need this fake level, you should use the SynchronizationContext implementations from the source Async CTP. It comes with three SynchronizationContext implementations that can be used for testing: universal (similar to my AsyncContext ), one for WinForms and one for WPF.

+6
source

Source: https://habr.com/ru/post/1240592/


All Articles