测试调用 BackgroundWorker 的方法

Testing a method that calls a BackgroundWorker

描述

考虑如下 class。它有一个 BackgroundWorker 作为一个 属性,以及一个让它报告进度的方法:

public class MyClass
{
    protected BackgroundWorker _worker;

    public MyClass(BackgroundWorker worker)
    {
        _worker = worker;
    }

    public void ReportProgress(int percentage)
    {
        _worker.ReportProgress(percentage);
    }
}

问题

ReportProgress()应该检测吗?

如果以上问题的答案是“是”?怎么办?已尝试使用 FakeItEasy 进行以下测试:

[Test]
public void ReportProgress_Test()
{
    // arrange
    var fakeWorker = A.Fake<System.ComponentModel.BackgroundWorker>();
    fakeWorker.WorkerReportsProgress = true;
    MyClass underTest = new MyClass(fakeWorker);

    // act
    underTest.ReportProgress(percentage);
    
    // assert
    A.CallTo(() => fakeWorker.ReportProgress(percentage)).MustHaveHappened();
}

此测试产生以下错误:

Message: FakeItEasy.Configuration.FakeConfigurationException : 

  The current proxy generator can not intercept the method System.ComponentModel.BackgroundWorker.ReportProgress(System.Int32 percentProgress) for the following reason:
    - Non-virtual members can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.

一种选择是引入一个界面,如评论中所述。如果后台工作人员的唯一用途是报告进度,这可能是个好主意。

但并非所有测试都需要对所有依赖项使用 Mocks,在许多情况下使用真实的具体对象也可以。这将导致测试同时测试两个对象以及它们之间的交互。在某些情况下,这将是有益的,因为它会捕获不正确的用法,在其他情况下,您可能希望单独测试它们以降低复杂性。我不认为一种方法适用于所有情况。

在这种情况下应该相当简单,只要调用 ReportProgress 就应该引发 ProgressChanged 事件。因此,只需将事件处理程序附加到事件并检查它是否提供预期结果。 IE。像这样。

    public void TestProgress()
    {
        var bw = new BackgroundWorker();
        int progress = 0;
        bw.ProgressChanged += (o, e) => progress = e.ProgressPercentage;

        var underTest = new MyClass(bw);
        underTest.ReportProgress(42);
        Assert.AreEqual(progress, 42);

    }

“是否应该测试报告进度”的问题是基于情况和意见的。我认为测试 one-line 方法的价值相当低,但如果是更大系统的一部分,进度报告可能对测试很有价值。