【问题标题】:Task.ContinueWith and DispatcherSynchronizationContextTask.ContinueWith 和 DispatcherSynchronizationContext
【发布时间】:2013-12-05 23:19:35
【问题描述】:

在对使用任务延续和 DispatcherSynchrinizationContext 的代码进行单元测试时,我遇到了一个我不明白的问题。

我的单元测试代码:

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext());

        var class1 = new Class1();
        var result = class1.MyAsyncMethod().Result;

        Assert.IsTrue(result == "OK");
    }
}

正在测试的代码:

class Class1
{
    public Task<string> MyAsyncMethod()
    {
        var tcs = new TaskCompletionSource<string>();

        MyInnerAsyncMethod()
            .ContinueWith(t =>
            {
                // Never reached if TaskScheduler.FromCurrentSynchronizationContext() is set
                tcs.SetResult("OK");

            }, TaskScheduler.FromCurrentSynchronizationContext());

        return tcs.Task;
    }


    private Task<string> MyInnerAsyncMethod()
    {
        var tcs = new TaskCompletionSource<string>();
        tcs.SetResult("OK");
        return tcs.Task;
    }
}

问题是“ContinueWith”方法中包含的代码永远不会到达如果我指定“TaskScheduler.FromCurrentSynchronizationContext()”。如果我删除此参数,则继续执行正确...

有什么想法或建议吗?

【问题讨论】:

  • 为什么这种行为会让您感到惊讶?你希望FromCurrentSynchronizationContext() 在这里做什么?
  • 应该调用“ContinueWith”中的代码,但不是我上面解释的

标签: wpf unit-testing task-parallel-library dispatcher


【解决方案1】:

我认为这是因为虽然您已经创建了一个新的 DispatcherSynchronisationContext,但没有实际线程运行调度循环以供您执行任务。

试着把它放在你的测试开始:

// Create a thread
Thread newWindowThread = new Thread(new ThreadStart( () =>
{
    // Create our context, and install it:
    SynchronizationContext.SetSynchronizationContext(
        new DispatcherSynchronizationContext(
            Dispatcher.CurrentDispatcher));

    // Start the Dispatcher Processing
    System.Windows.Threading.Dispatcher.Run();
}));

礼貌: http://reedcopsey.com/2011/11/28/launching-a-wpf-window-in-a-separate-thread-part-1/

【讨论】:

    【解决方案2】:

    lain你让我走对了,谢谢!!

    我没有修改我正在测试的代码,这是一个新的测试代码实现,可以按预期工作:

    [TestClass]
    public class UnitTest1
    {
        private ExecutionContext _executionContext;
    
        [TestInitialize]
        public void OnSetup()
        {
            _executionContext = CreateExecutionContext();
    
            SynchronizationContext.SetSynchronizationContext(_executionContext.DispatcherSynchronizationContext);
        }
    
        [TestCleanup]
        public void OnTearDown()
        {
            // stops the dispatcher loop
            _executionContext.Dispatcher.InvokeShutdown();
        }
    
        [TestMethod]
        public void TestMethod1()
        {
            var class1 = new Class1();
            var result = class1.MyAsyncMethod().Result;
    
            Assert.IsTrue(result == "OK");
        }
    
        /* Helper classes and methods */
    
        private ExecutionContext CreateExecutionContext()
        {
            var tcs = new TaskCompletionSource<ExecutionContext>();
    
            var mockUIThread = new Thread(() =>
                    {
                        // Create the context, and install it:
                        var dispatcher = Dispatcher.CurrentDispatcher;
                        var syncContext = new DispatcherSynchronizationContext(dispatcher);
    
                        SynchronizationContext.SetSynchronizationContext(syncContext);
    
                        tcs.SetResult(new ExecutionContext
                            {
                                DispatcherSynchronizationContext = syncContext, 
                                Dispatcher = dispatcher
                            });
    
                        // Start the Dispatcher Processing
                        Dispatcher.Run();
                    });
    
            mockUIThread.SetApartmentState(ApartmentState.STA);
            mockUIThread.Start();
    
            return tcs.Task.Result;
        }
    
        internal class ExecutionContext
        {
            public DispatcherSynchronizationContext DispatcherSynchronizationContext { get; set; }
            public Dispatcher Dispatcher { get; set; }
        }
    
        /*  ------   */
    
    }
    

    【讨论】:

      猜你喜欢
      • 2022-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多