我正在尝试围绕自定义SynchronizationContext
实现编写单元测试。
此类的两个重要操作是Send
和Post
,其中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
不阻止,但代理 都被调用?
答案 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);
不知道这是否真的有用,你必须检查。