问题描述
说明
请考虑以下类。它具有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);
}
“应该测试报告进度”的问题将基于情况和观点。我认为测试单行方法的价值不高,但是,如果是更大系统的一部分,则进度报告可能非常有价值。