2012-12-30 22 views
4

我有Visual Studio 2012和需要同步上下文的异步测试。
但MSTest的默认同步上下文为空。
我想测试在具有同步上下文的WPF或WinForms-UI线程上运行。
将SynchronizationContext添加到测试线程的最佳方法是什么?如何将同步上下文添加到异步测试方法

[TestMethod] 
    public async Task MyTest() 
    { 
     Assert.IsNotNull(SynchronizationContext.Current); 
     await MyTestAsync(); 
     DoSomethingOnTheSameThread(); 
    } 

回答

5

运用帕纳约蒂斯Kanavos和斯蒂芬·克利里的信息,我可以写我的testmethods这样的:

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

内的代码现在在WPF同步上下文中运行并处理为用于MSTest的所有异常。 帮手方法来自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

您可以创建自定义的SynchronizationContext派生类并将其注册为与SynchronizationContext.SetSynchronizationContext当前上下文。阅读Stephen Toub在“Await, SynchronizationContext, and Console Apps”和“Await, SynchronizationContext, and Console Apps: Part 2”上的帖子。

您的自定义的SynchronizationContext只覆盖接收异步执行回调Post方法。你如何执行它取决于你。

第一柱提供,其存储在队列中和阻挡环从所述队列中取出的动作和在单个线程中执行它们所有张贴动作的同步环境。

6

你可以使用一个线程在我AsyncEx library称为AsyncContextSynchronizationContext

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

然而,这并不能完全假的特定UI环境,例如,Dispatcher.CurrentDispatcher仍将null。如果您需要这种伪造程度,您应该使用原始Async CTP中的SynchronizationContext实现。它附带三个可用于测试的SynchronizationContext实现:一个通用目标(类似于我的AsyncContext),一个用于WinForms,另一个用于WPF。