测试调用BackgroundWorker的方法

问题描述

说明

请考虑以下类。它具有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,在许多情况下使用真正的具体对象也可以。这将导致测试同时测试两个对象以及它们之间的交互。在某些情况下,这将是有益的,因为它将捕获不正确的用法,而在其他情况下,您可能希望单独测试它们以降低复杂性。我认为没有一种方法适合所有情况。

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

    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);

    }

“应该测试报告进度”的问题将基于情况和观点。我认为测试单行方法的价值不高,但是,如果是更大系统的一部分,则进度报告可能非常有价值。