我有一个可启动计时器的模拟对象,需要在测试中将其丢弃。处置模拟对象的正确方法是什么?在我要嘲笑的课堂上,我有:
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
// Stop and dispose timer here.
}
_disposed = true;
}
}
public void Dispose()
{
Dispose(true);
}
所以现在在我的测试中,我需要模拟对象,使用它,然后确保将其丢弃。我知道我可以设置CallBase = true
,但是我不确定这是否是正确的(行业标准)处理方式:
[TestMethod]
public void TestSomething()
{
var mock = new Mock<ObjectWithTimer>() { CallBase = true };
using (var foo = mock.Object)
{
foo.DoSomething(); // This consequently starts a timer.
} // Here, Dispose() will be called.
}
using块结束时,将调用Dispose()
,它会调用基础Dispose(bool)
。但是,是否可以在不向我的模拟中添加CallBase = true
的情况下进行此处理?当我需要模拟来覆盖其他方法时,这是不理想的。
答案 0 :(得分:0)
如果您松开两个类之间的耦合,也许可以解决问题,从而使模拟更加通用。如果您的被测类不直接使用ObjectWithTimer
,而是使用ObjectWithTimer
实现的接口,则可以这样做。
示例:
public interface IObjectWithTimer : IDisposable
{
void DoSomething();
}
public class ObjectWithTimer : IObjectWithTimer
{
// ...
}
public class ClassUnderTest
{
public ClassUnderTest(IObjectWithTimer timer)
{
// ...
}
public void ThisShouldCallDisposeOnTimer()
{
// ...
}
}
然后您的测试代码如下:
[TestMethod]
public void ShouldCallDispose()
{
var mock = new Mock<IObjectWithTimer>();
var classUnderTest = new ClassUnderTest(mock.Object);
classUnderTest.ThisShouldCallDisposeOnTimer();
mock.Verify(x => x.Dispose(), Times.Once());
}
这样,您的测试就完全与计时器分配逻辑分离了,这实际上不是您要测试的。
答案 1 :(得分:0)
通过使用new Mock<ObjectWithTimer>()
,您的代码没有与该类的实现完全分开,因为该方法提供了一个从您的具体实现派生的模拟类,而该类(如您已经明确地知道的那样)不是真的是您想要您的模拟物做什么。
为ObjectWithTimer
创建一个接口。该接口应包括有关该类的所有公开内容。由于类为IDisposable
,因此您的接口应从该接口派生。将依赖于该类的代码改为依赖于接口,并更改测试以模拟接口而不是类。
现在您使用的是正确的Mock对象,您的测试可能需要定义该模拟的预期行为。使用模拟对象时,这是正常现象,正确模拟行为很重要,否则您的测试将一文不值(当实际代码可能失败时,测试可能会通过)。
现在,调用代码与该接口的实现已完全分离,因此不再需要具体实现类(ObjectWithTimer)。