我是单元测试的新手,我经常听到“模拟对象”的说法。用外行的话来说,有人能解释一下什么是模拟对象,以及它们在编写单元测试时通常用于什么?
发布于 2010-09-02 06:04:55
模拟对象是替代真实对象的对象。在面向对象编程中,模拟对象是以受控方式模仿真实对象行为的模拟对象。
计算机程序员通常创建模拟对象来测试某些其他对象的行为,这与汽车设计者使用碰撞测试假人来模拟人在车辆碰撞中的动态行为非常相似。
http://en.wikipedia.org/wiki/Mock_object
模拟对象允许您设置测试场景,而无需使用大型、笨重的资源,如数据库。您可以在单元测试中使用模拟对象模拟数据库,而不是调用数据库进行测试。这使您摆脱了必须设置和拆卸实际数据库的负担,仅仅是为了在类中测试单个方法。
单词"Mock“有时错误地与”Stub“互换使用。这两个词之间的区别本质上是described here.,mock是一个存根对象,它还包括对被测对象/方法的正确行为的期望(即“断言”)。
例如:
class OrderInteractionTester...
public void testOrderSendsMailIfUnfilled() {
Order order = new Order(TALISKER, 51);
Mock warehouse = mock(Warehouse.class);
Mock mailer = mock(MailService.class);
order.setMailer((MailService) mailer.proxy());
mailer.expects(once()).method("send");
warehouse.expects(once()).method("hasInventory")
.withAnyArguments()
.will(returnValue(false));
order.fill((Warehouse) warehouse.proxy());
}
}
注意,使用预期的结果对warehouse
和mailer
模拟对象进行了编程。
发布于 2010-09-02 06:21:28
模拟对象是一种Test Double。您正在使用mockobjects来测试和验证被测类与其他类的协议/交互。
通常,你会“编程”或“记录”期望:你期望你的类对底层对象进行的方法调用。
比方说,我们正在测试一个服务方法来更新Widget中的字段。在您的体系结构中,有一个处理数据库的WidgetDAO。与数据库的对话很慢,设置和事后清理也很复杂,所以我们将模拟WidgetDao。
让我们考虑一下服务必须做什么:它应该从数据库中获取一个Widget,使用它做一些事情,然后再次保存它。
因此,在带有伪模拟库的伪语言中,我们会有如下内容:
Widget sampleWidget = new Widget();
WidgetDao mock = createMock(WidgetDao.class);
WidgetService svc = new WidgetService(mock);
// record expected calls on the dao
expect(mock.getById(id)).andReturn(sampleWidget);
expect(mock.save(sampleWidget);
// turn the dao in replay mode
replay(mock);
svc.updateWidgetPrice(id,newPrice);
verify(mock); // verify the expected calls were made
assertEquals(newPrice,sampleWidget.getPrice());
通过这种方式,我们可以很容易地测试驱动依赖于其他类的类的开发。
发布于 2010-09-02 06:18:08
我强烈推荐一个great article by Martin Fowler,解释模拟到底是什么,以及它们与存根有何不同。
https://stackoverflow.com/questions/3622455
复制相似问题