我刚刚阅读了有关模拟对象的维基百科文章,但我仍然不完全清楚它们的用途.当实际对象过于复杂或不可预测时,它们似乎是由测试框架创建的对象(您知道100%确定模拟对象的值是什么,因为您完全控制它们).
但是,我的印象是所有测试都是使用已知值的对象完成的,所以我必须遗漏一些东西.例如,在课程项目中,我们负责日历应用程序.我们的测试套件由事件对象组成,我们确切知道它们是什么,因此我们可以测试多个事件对象,各种子系统和用户界面之间的交互.我猜这些是模拟对象,但我不知道你为什么不这样做,因为没有已知值的对象,你无法测试系统.
模拟对象不仅仅是具有已知值的对象.它是一个与复杂对象具有相同接口的对象,您无法在测试中使用它(如数据库连接和结果集),但是您可以在测试中控制该实现.
有一些模拟框架允许你动态创建这些对象,实质上允许你这样说:用一个方法foo让我成为一个对象,它接受一个int并返回一个bool.当我传递0时,它应该返回true.然后你可以测试使用foo()的代码,以确保它做出适当的反应.
马丁福勒有一篇关于嘲笑的好文章:
http://martinfowler.com/articles/mocksArentStubs.html
想想拥有客户端和服务器软件的经典案例.要测试客户端,您需要服务器; 要测试服务器,您需要客户端.这使得单元测试几乎不可能 - 不使用模拟.如果模拟服务器,则可以单独测试客户端,反之亦然.
模拟的重点不是复制它模仿的东西的行为.它更像是一个简单的状态机,其状态变化可以通过测试框架进行分析.因此,客户端模拟可能会生成测试数据,将其发送到服务器,然后分析响应.您希望对特定请求做出某种响应,因此您可以测试是否获得了该请求.
我同意@Lou Franco所说的一切,你一定应该阅读@Lou Franco指出的关于测试双打的优秀Martin Fowler文章.
任何测试double(假,存根或模拟)的主要目的是隔离被测对象,以便您的单元测试仅测试该对象(而不是它的依赖关系以及它与之协作或交互的其他类型).
可以使用提供对象所依赖的接口的对象来代替实际的依赖关系,以便可以预期会发生某些交互.这可能很有用,但围绕基于状态和基于交互的测试存在一些争议.过度使用模拟期望将导致脆弱的测试.
测试双精度的另一个原因是删除对数据库或文件系统或其他昂贵的设置或执行耗时操作的类型的依赖性.这意味着您可以将您感兴趣的对象单元测试所需的时间保持在最低限度.