什么是模拟,什么时候应该使用它?

时间:2008-10-17 22:49:51

标签: testing mocking glossary

我刚刚阅读了mock objects上的维基百科文章,但我仍然不完全清楚他们的目的。当实际对象过于复杂或不可预测时,它们似乎是由测试框架创建的对象(您知道100%确定模拟对象的值是什么,因为您完全控制它们)。

然而,我的印象是所有测试都是使用已知值的对象完成的,所以我必须遗漏一些东西。例如,在课程项目中,我们负责日历应用程序。我们的测试套件由事件对象组成,我们确切知道它们是什么,因此我们可以测试多个事件对象,各种子系统和用户界面之间的交互。我猜这些是模拟对象,但我不知道你为什么不这样做,因为没有已知值的对象,你就无法测试系统。

5 个答案:

答案 0 :(得分:27)

模拟对象不仅仅是具有已知值的对象。它是一个与复杂对象具有相同接口的对象,您无法在测试中使用它(如数据库连接和结果集),但是您可以在测试中控制该实现。

有一些模拟框架允许你动态创建这些对象,实质上允许你说出这样的话:用一个方法foo创建一个对象,它接受一个int并返回一个bool。当我传递0时,它应该返回true。然后你可以测试使用foo()的代码,以确保它做出适当的反应。

Martin Fowler有一篇关于嘲笑的好文章:

答案 1 :(得分:9)

想想拥有客户端和服务器软件的经典案例。要测试客户端,您需要服务器;要测试服务器,您需要客户端。这使得单元测试几乎不可能 - 不使用模拟。如果您模拟服务器,则可以单独测试客户端,反之亦然。

模拟的重点不是复制它嘲弄的东西的行为。它更像是一个简单的状态机,其状态变化可以通过测试框架进行分析。因此,客户端模拟可能会生成测试数据,将其发送到服务器,然后分析响应。您希望对特定请求做出某种响应,因此您可以测试是否得到它。

答案 2 :(得分:6)

我同意@Lou Franco所说的一切,你绝对应该阅读@Lou Franco指出的关于测试双打的优秀Martin Fowler文章。

任何测试double(假,存根或模拟)的主要目的是隔离被测对象,以便您的单元测试仅测试该对象(而不是它的依赖关系以及它与之协作或交互的其他类型)。 / p>

可以使用提供对象所依赖的接口的对象来代替实际的依赖关系,以便可以预期会发生某些交互。这可能很有用,但围绕基于状态和基于交互的测试存在一些争议。过度使用模拟期望将导致脆弱的测试。

测试双精度的另一个原因是删除对数据库或文件系统或其他昂贵的设置或执行耗时操作的依赖性。这意味着您可以将您感兴趣的对象单元测试所需的时间保持在最低限度。

答案 3 :(得分:2)

以下是一个示例:如果您正在编写填充数据库的代码,则可能需要检查特定方法是否已将数据添加到数据库中。

设置数据库的副本以进行测试存在的问题是,如果假设在调用测试方法之前没有记录,之后有一条记录,则需要将数据库回滚到先前的状态,从而添加运行测试的开销。

如果您假设只有一个记录比以前多一个,它可能会与连接到同一数据库的第二个测试人员(甚至是同一代码中的第二个测试人员)发生冲突,从而导致依赖性并使测试变得脆弱。

模拟允许您保持测试彼此独立并易于设置。

这只是一个例子 - 我相信其他人可以提供更多。

我同意其他贡献者100%同意这个主题,特别是对Martin Fowler文章的建议。

答案 4 :(得分:0)

您可能对我们的图书感兴趣,请参阅http://www.growing-object-oriented-software.com/。它是用Java编写的,但这些想法仍然适用。