如何使Mock对象与目标对象保持同步

时间:2011-03-07 01:29:58

标签: unit-testing version-control junit mocking

我问的是模拟对象管理,无论具体实现如何(EasyMock,Mock Object等)。

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

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

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

4 个答案:

答案 0 :(得分:2)

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

您可以通过以下方式降低行为偏离的风险:

  • 集成测试,
  • 将模拟数据与实际实施进行比较。

答案 1 :(得分:0)

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

总的来说,我将测试集中在公共界面上。如果您的公共界面发生变化,您可能需要更改的不仅仅是测试。

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

那就是说,我试着变得灵活。如果在给定的情况下测试模拟行为是有意义的,我将使用它。如果我需要暴露内部以获得合适的覆盖率,我会。

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

答案 2 :(得分:0)

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

答案 3 :(得分:0)

如果ClassA致电:

 AThing aThing = ClassB.GiveMeAThing()

ClassA永远不应该关心ClassB如何获取该东西。因此,存根 - StubB - 永远不应该关心存根的真实实现是如何表现的。只有当交互本身发生变化 - 返回类型或调用参数 - 才应该更改StubB,如果您希望编译代码,则需要这样做:-)

如果您的ClassB开始返回Nulls或引发新类型的异常;那么,有一些全新的测试要编写,也可能是新的存根。

此致 的Morten