2011-03-07 49 views
4

我在问关于模拟对象管理,无论具体实现(EasyMock,Mock Object等)。如何保持Mock对象与目标对象同步

我一直不愿意在我的单元测试中使用Mock对象,原因如下: Mock对象的行为必须镜像被模拟对象的行为。如果被模拟对象的行为发生了变化,我们也必须改变模拟对象的行为。如果我们不这样做,模拟对象的行为将与实际对象不同步,从而使单元测试变得毫无意义,而且这是危险的。

我的问题是, 如何保持模拟对象与目标对象同步? 你如何传播变化? 您是否使用任何模拟对象管理技术?

编辑: 更改标题以缩小范围。

回答

2

定义良好的API不应该有这样的余地:给定一组输入,被模拟的对象应该只能以这些特定的方式运行:行为与接口绑定。如果允许有差异,那么你的模拟对象应该测试这个对象可以做的所有不同的事情。

可以减轻行为漂移的风险:

  • 集成测试,并
  • 与实际执行的比较数据嘲笑。
0

你在正确的轨道上。您不需要每次重构被测系统时都必须更改的脆弱测试。

一般来说,我将测试集中在公共接口上。如果你的公共接口改变了,你可能不得不改变测试。

我也尝试做状态测试,而不是行为测试,只要有可能。所以我通常会使用stubs instead of mocks。 (大多数隔离/模拟框架可以让你创建。)我验证被测系统(或类)的状态,而不是让一个模拟对象来验证自己。

这就是说,我尽量保持灵活。如果在特定情况下测试模拟行为是有意义的,我会使用它。如果我需要揭露内部机构以获得体面的覆盖面,我会的。

编辑:另请参阅此article by Scott Bain

0

我不是专家,但我的想法是,模拟对象是为单个测试用例/交互设计的。如果这种互动发生变化,您显然希望这些反映在您的测试中。但是,当它们检查可能仍然有效的不同交互时,这不应该破坏类的所有模拟对象。

0

如果ClassA的来电:

AThing aThing = ClassB.GiveMeAThing() 

ClassA的不应该关心ClassB的如何得到那个东西。因此,一个存根StubB永远不应该关心存根的真正实现如何表现。只有当交互本身改变 - 返回类型或调用参数 - StubB应该被改变,并且如果你想让你的代码编译,那将需要:-)

如果你的ClassB开始返回Nulls或Throws新类型的异常;那么,那么就会有全新的测试被写入,并且可能还有新的存根。

Regards, Morten