4

与使用模拟对象相比,哪些场景、应用程序/系统的区域等最适合基于“经典”状态的测试?

4

6 回答 6

10

我将从 TDD/BDD 的角度来解决它,测试驱动设计。

首先,这取决于您购买的设计风格,因为请记住这是关于设计的第一。正如 Martin Fowler 在这篇出色的文章Mocks Aren't Stubs中所讨论的,有两种思想流派,它们确实产生了不同类型的设计。

如果你想接受 mockist 方法,那么我强烈建议你从mockobjects 网站和他们的文章Mock Roles, Not Objects开始。他们还出版了一本书

事实是,即使您确实认为 mock-first 设计风格不适合您,或者您不想直接通过您的应用程序(例如,不是在测试您的域/服务层时),那么您仍然会想使用测试替身。xUnit 测试模式解释了不同类型的测试替身及其用途。

就我个人而言,我从不模拟域类,所以从不模拟实体/值对象. 然而我最近一直在尝试模拟对象风格的方法,它确实改变了我的设计,我觉得工作风格很舒服。在 MVC 应用程序中以这种风格工作我可能会从一个自动化的验收测试开始,然后我将编写一个模拟任何非域对象(例如存储库/服务)的控制器测试,然后我将继续进行测试这些存储库/服务再次模拟了它们的依赖关系。当我到达一个没有麻烦依赖关系的类(例如域实体/值对象)时,我会停下来。我可以继续测试特定的角色接口,然后由我的域类实现,这是 mockobjects 家伙推荐的,但我目前没有看到这种方法有很多价值。

显然值得补充的是,测试设计在这里很重要,但请记住,尽管 90% 的 IoC/mocking/DIP 示例显示接口-实现对(ICustomerRepository/CustomerRepository),但寻找角色接口有很多价值。

于 2008-09-12T08:10:54.150 回答
3

您应该对依赖项使用模拟。我不认为这是非此即彼的;通常,您将为依赖项创建模拟,对它们设置期望(无论是调用还是状态),然后运行被测单元。然后你会检查它的状态,然后验证对模拟的期望。

于 2008-09-10T18:29:10.450 回答
3

使用模拟对象并不意味着您没有进行基于状态的测试。

于 2008-09-10T18:39:09.773 回答
1

在使用服务时,无论是我自己的还是第三方的,我理所当然地设计接口,所以我倾向于关注那里的交互。这鼓励我设计最小的界面。

我检查任何关注值对象的状态,就像简单的计算、查找等。

下次您发现自己设计的东西通常遵循模型/视图/控制器或演示者时,我强烈建议您尝试使用模型和视图接口的演示者优先方法(谷歌搜索)。这将使您对如何有效地使用存根/模拟有一个很好的感觉。

于 2010-01-19T16:23:33.940 回答
0

它的风格问题.. Mockist vs Classic TDDers。
就个人而言..我会尽可能地测试真实的课程。尽可能淡化 Mocks;仅用于解耦诸如 IO(文件系统、数据库连接、网络)、第三方组件等缓慢/难以测试的事物。

于 2008-09-10T19:26:23.637 回答
0

作为一名经验丰富的 TDD'er,这是我经常被其他开发人员问到的问题。对我来说,卷入 Mockist 与 Classicist 的辩论是错误的,因为这样的讨论具有误导性。基于状态和基于行为的单元测试是您工具箱中的两种不同工具,它们没有理由相互排斥。

当您想在与对象的外部接口交谈后查询对象的内部属性时,基于状态的单元测试是合适的。如果它的一个或多个协作者涉及对其他对象的潜在昂贵调用,那么无论如何都要存根这些调用并简单地忽略协作者。

当您想要考虑单元测试的“如何”并专注于发现对象之间的关系时,基于行为的单元测试是一个好主意,而不是基于状态的单元测试的传统“什么”问题。如果您希望断言以某种方式和/或顺序使用协作者,请使用模拟 - 提供断言的存根。

我建议您专注于标准单元测试实践——尽可能少地使用生产代码,并且每次测试都有一个断言。这将迫使你思考“我想在这个测试中练习和断言的究竟是什么?”,这个问题的答案将帮助你选择正确的单元测试工具。

于 2008-09-11T22:38:05.400 回答