我正在尝试测试我的类如何对BackgroundWorker触发RunWorkerCompleted事件时发生的事情做出反应。
我正在使用RhinoMocks(如果有其他方法我也愿意尝试)并且代码如下:
//arrange
var bw1 = MockRepository.GenerateStub<BackgroundWorker>();
Action work1 = () => Thread.Sleep(1);
WorkQueueProcess processInQueue = new WorkQueueProcess(bw1) { Work = work1 };
var tested = new WorkQueue() { processInQueue };
// act
bw1.Raise(
bw => bw.RunWorkerCompleted +=
null,
bw1,
new RunWorkerCompletedEventArgs(null, null, false)
);
// assert
Assert.AreEqual(false, tested.IsBusy);
我得到的例外情况是:
无效通话,最后一次通话 使用过或没有打过电话(制作 确定你正在呼叫虚拟 (C#)/ Overridable(VB)方法)。
我做错了什么?是因为BackgroundWorker没有虚拟方法吗?我认为我应该能够举办一场活动,因为活动几乎不会虚拟。
答案 0 :(得分:1)
只有定义事件的类才能引发该事件。这就是.NET中事件系统的工作原理。
RhinoMocks提供的Raise方法旨在与定义事件的接口一起使用。在这种情况下,任何实现该接口的类都拥有自己的事件,因此能够引发它。对于RhinoMocks生成的运行时发出的类型也是如此。
然而,当涉及到类时,即使是子类型也不能引发由其超类型定义的事件,这就是为什么我们有OnEvent编码习语。
BackgroundWorker确实具有将引发事件的OnRunWorkerCompleted方法。这个方法是虚拟的,所以如果你能让RhinoMocks调用这个受保护的方法,你应该能够引发这个事件。
我正在使用Moq,无法这样做 - 我不记得RhinoMocks是否有能力调用受保护的成员。
否则,您可以从BackgroundWorker派生特定于测试的类,并添加一个调用OnRunWorkerCompleted的公共方法。
然而,作为结束语,我强烈建议您不要尝试单元测试多线程代码 - 沿着这条路只是痛苦......