【问题标题】:How can I raise an event on a mocked BackgroundWorker?如何在模拟的 BackgroundWorker 上引发事件?
【发布时间】:2009-09-22 09:47:43
【问题描述】:

我正在尝试测试我的班级对 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#)/可覆盖(VB)方法)。

我做错了什么?是因为BackgroundWorker没有虚方法吗?我认为无论如何我都应该能够发起一个活动,因为活动几乎不是虚拟的。

【问题讨论】:

    标签: unit-testing rhino-mocks


    【解决方案1】:

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

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

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

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

    我使用的是最小起订量,不能这样做 - 我不记得 RhinoMocks 是否有能力调用受保护的成员。

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

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

    【讨论】:

    • 非常感谢你让我想起了这个成语(OnEvent 成语),虽然我以前也遇到过,但我没有想到。 RhinoMocks 似乎无法调用受保护的成员,但创建我自己的后台工作人员模拟似乎可以完成这项工作。我正在尝试测试我的对象是否会对后台工作人员结果做出正确反应,我什至不会尝试多线程单元测试。不过感谢您的警告。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-12
    • 2011-08-31
    • 1970-01-01
    相关资源
    最近更新 更多