5

我正在尝试围绕自定义SynchronizationContext实现编写单元测试。

此类的两个重要操作是SendPost,其中Send同步Post调用委托和异步调用委托。

我想编写单元测试来验证这种行为,代表是同步或异步执行的。我不希望测试依赖于成功案例的延迟,因为它人为地延长了测试的执行时间(但失败导致延迟是合理的)。

最初,我考虑过使用 Tasks 来表示委托的执行:

var tcs = new TaskCompletionSource<object>();

var context = new CustomSynchronizationContext();

context.Send((state) => tcs.SetResult(null), null);

// Task should already be completed!
Assert.IsTrue(this.tcs.Task.IsCompleted);

但是,这并不能确保在测试运行程序可以继续之前,委托不会很快异步执行。

如何围绕上下文安排测试以确保Send完成委托的块和Post不完成委托,但委托被调用?

4

2 回答 2

3

我相信您可以使用一对ManualResetEvents来实现这一点。使用下面的代码,只有在测试失败时才会出现减速(数字非常高,可能会安全地减少)。这里的想法是我们断言事情必须发生的顺序,只有在我们阻塞或不阻塞时才会发生。

对于同步测试:

var incall = new ManualResetEvent(false);
var unblock = new ManualResetEvent(false);
var context = new CustomSynchronizationContext();
var t = Task.Run(() => context.Send(state =>
{
    incall.Set();
    unblock.WaitOne(5000);
}, null));
Assert.IsTrue(incall.WaitOne(1000));
Assert.IsFalse(t.Wait(10));
unblock.Set();
Assert.IsTrue(t.Wait(1000));

对于异步测试:

var incall = new ManualResetEvent(false);
var unblock = new ManualResetEvent(false);
var context = new CustomSynchronizationContext();
var t = Task.Run(() =>context.Post(state =>
{
    incall.Set();
    unblock.WaitOne(5000);
}, null));
Assert.IsTrue(incall.WaitOne(1000));
Assert.IsTrue(t.Wait(1000)); //This will timeout if unblock is blocking completion of the task
unblock.Set();
于 2013-06-17T17:38:28.170 回答
-1

结合我的想法:

var mainThreadId = Thread.ManagedThreadId;
var sendThreadId;
context.Send((state) => sendThreadId = Thread.ManagedThreadId);
Assert.AreEqual(mainThreadId, sendThreadId);

不知道这是否真的有效,你必须检查一下。

于 2013-06-13T09:36:40.147 回答