Task.ContinueWith和DispatcherSynchronizationContext

2019-10-29 17:26发布

我面对的是,当单元测试使用任务延续和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()”。 如果我删除此参数,延续执行正确...

任何意见或建议?

Answer 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/



Answer 2:

躺在你把我放在正确的方式,谢谢!

我没有改变我的代码进行测试,这里是一个新的执行测试代码按预期工作的:

[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; }
    }

    /*  ------   */

}


文章来源: Task.ContinueWith and DispatcherSynchronizationContext