如何在必要时测试实现是同步还是异步?

时间:2013-06-13 09:13:00

标签: c# unit-testing asynchronous synchronization

我正在尝试围绕自定义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不阻止,但代理 都被调用?

2 个答案:

答案 0 :(得分: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();

答案 1 :(得分:-1)

结合我的想法:

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

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