长期协调取消
我正在为我的应用程序的“粘合”层编写单元测试,并且难以为异步方法创建确定性测试,这些异步方法允许用户提前取消操作。
具体来说,在一些异步方法中,我们有代码对取消调用做出反应,并确保对象在完成之前处于适当状态。 我想确保这些代码路径被测试覆盖。
在这种情况下举例说明典型的异步方法的一些C#伪代码如下所示:
public void FooAsync(CancellationToken token, Action<FooCompletedEventArgs> callback)
{
if (token.IsCancellationRequested) DoSomeCleanup0();
// Call the four helper methods, checking for cancellations in between each
Exception encounteredException;
try
{
MyDependency.DoExpensiveStuff1();
if (token.IsCancellationRequested) DoSomeCleanup1();
MyDependency.DoExpensiveStuff2();
if (token.IsCancellationRequested) DoSomeCleanup2();
MyDependency.DoExpensiveStuff3();
if (token.IsCancellationRequested) DoSomeCleanup3();
MyDependency.DoExpensiveStuff4();
if (token.IsCancellationRequested) DoSomeCleanup4();
}
catch (Exception e)
{
encounteredException = e;
}
if (!token.IsCancellationRequested)
{
var args = new FooCompletedEventArgs(a bunch of params);
callback(args);
}
}
到目前为止,我所提出的解决方案涉及嘲笑由胶合层包装的基础MyDependency
操作,并强制每个人在任意时间段内休眠。 然后我调用异步方法,并告诉我的单元测试在取消异步请求之前休眠数毫秒。
像这样的东西(以Rhino Mocks为例):
[TestMethod]
public void FooAsyncTest_CancelAfter2()
{
// arrange
var myDependency = MockRepository.GenerateStub<IMyDependency>();
// Set these stubs up to take a little bit of time each so we can orcestrate the cancels
myDependency.Stub(x => x.DoExpensiveStuff1()).WhenCalled(x => Thread.Sleep(100));
myDependency.Stub(x => x.DoExpensiveStuff2()).WhenCalled(x => Thread.Sleep(100));
myDependency.Stub(x => x.DoExpensiveStuff3()).WhenCalled(x => Thread.Sleep(100));
myDependency.Stub(x => x.DoExpensiveStuff4()).WhenCalled(x => Thread.Sleep(100));
// act
var target = new FooClass(myDependency);
CancellationTokenSource cts = new CancellationTokenSource();
bool wasCancelled = false;
target.FooAsync(
cts.Token,
args =>
{
wasCancelled = args.IsCancelled;
// Some other code to manipulate FooCompletedEventArgs
});
// sleep long enough for two operations to complete, then cancel
Thread.Sleep(250);
cts.Cancel();
// Some code to ensure the async call completes goes here
//assert
Assert.IsTrue(wasCancelled);
// Other assertions to validate state of target go here
}
除了在单元测试中使用Thread.Sleep使我感到不安,更大的问题在于,如果偶尔会在构建服务器上进行测试,但是如果这种测试恰好处于重大负载下,则此类测试会失败。 异步呼叫太过分了,取消来得太迟。
任何人都可以提供更可靠的单元测试取消逻辑,用于这样的长时间运行操作吗? 任何想法,将不胜感激。
我会尝试使用mock以同步方式“模拟”异步行为。 而不是使用
myDependency.Stub(x => x.DoExpensiveStuff1()).WhenCalled(x => Thread.Sleep(100));
然后在任意数量的毫秒内设置取消标志,我将其设置为回调的一部分:
myDependency.Stub(x => x.DoExpensiveStuff1());
myDependency.Stub(x => x.DoExpensiveStuff2());
myDependency.Stub(x => x.DoExpensiveStuff3()).WhenCalled(x => cts.Cancel());
myDependency.Stub(x => x.DoExpensiveStuff4());
从代码的角度来看,这看起来好像在通话过程中发生了取消。
每个长时间运行的操作应该在事件开始运行时触发。
把这个事件挂在单元测试中。 这给出了具有确定性的结果,这些事件在将来可能有用。
链接地址: http://www.djcxy.com/p/8959.html上一篇: Orchestrating cancellation in long
下一篇: Selenium syntax for Verifications that work with Hudson / jenkins