public void MyMethod() {
...
(new Action<string>(worker.DoWork)).BeginInvoke(myString, null, null);
...
}
我正在使用Unity,创建模拟对象并不是问题,但如何测试DoWork是否被调用而不必担心竞争条件呢? 先前的问题提供了一个解决方案,但在我看来,等待处理程序是一种hack(竞争条件仍然存在,尽管几乎不可能出现)。
编辑:好的,我原以为可以用一种非常普遍的方式提出这个问题,但看来我需要进一步阐述问题:
我想为上述的MyMethod创建一个测试,所以我会做类似于这样的事情:
[TestMethod]
public void TestMyMethod() {
...setup...
MockWorker worker = new MockWorker();
MyObject myObj = new MyObject(worker);
...assert preconditions...
myObj.MyMethod();
...assert postconditions...
}
一种天真的方法是创建一个MockWorker(),当DoWork被调用时仅设置一个标志,并在后置条件中测试该标志。这当然会导致竞态条件,即在MockWorker中设置标志之前就检查了后置条件。
更正确的方法(我可能最终会使用)是使用等待句柄:
class MockWorker : Worker {
public AutoResetEvent AutoResetEvent = new AutoResetEvent();
public override void DoWork(string arg) {
AutoResetEvent.Set();
}
}
...并使用以下断言:
Assert.IsTrue(worker.AutoResetEvent.WaitOne(1000, false));
这是采用类似信号量的方法,这很好...但是在理论上,以下情况可能发生:
- 在我的DoWork委托上调用BeginInvoke。
- 由于某种原因,主线程或DoWork线程都没有被分配执行时间1000ms。
- 主线程被分配执行时间,并且由于超时而导致断言失败,即使DoWork线程尚未被执行。
我是否误解了AutoResetEvent的工作方式?我是不是太过紧张,还是有一个聪明的解决方案来解决这个问题?