如何在模拟的BackgroundWorker上举办活动?

时间:2009-09-22 09:47:43

标签: unit-testing rhino-mocks

我正在尝试测试我的类如何对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没有虚拟方法吗?我认为我应该能够举办一场活动,因为活动几乎不会虚拟。

1 个答案:

答案 0 :(得分:1)

只有定义事件的类才能引发该事件。这就是.NET中事件系统的工作原理。

RhinoMocks提供的Raise方法旨在与定义事件的接口一起使用。在这种情况下,任何实现该接口的类都拥有自己的事件,因此能够引发它。对于RhinoMocks生成的运行时发出的类型也是如此。

然而,当涉及到类时,即使是子类型也不能引发由其超类型定义的事件,这就是为什么我们有OnEvent编码习语。

BackgroundWorker确实具有将引发事件的OnRunWorkerCompleted方法。这个方法是虚拟的,所以如果你能让RhinoMocks调用这个受保护的方法,你应该能够引发这个事件。

我正在使用Moq,无法这样做 - 我不记得RhinoMocks是否有能力调用受保护的成员。

否则,您可以从BackgroundWorker派生特定于测试的类,并添加一个调用OnRunWorkerCompleted的公共方法。

然而,作为结束语,我强烈建议您不要尝试单元测试多线程代码 - 沿着这条路只是痛苦......