我如何知道何时使用基于状态的测试与模拟测试?

时间:2008-09-10 18:27:39

标签: unit-testing

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

6 个答案:

答案 0 :(得分:9)

我将从TDD / BDD角度解决这个问题,测试正在推动设计。

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

如果您想购买mockist方法,我强烈建议您先查看mockobjects site及其文章Mock Roles, Not Objects。他们也有book出来。

事实是即使您确实认为模拟优先设计风格不适合您,或者您不希望通过您的应用程序直接执行(例如,在测试您的域/服务层时)你仍然想要使用测试双打。 xUnit Test Patterns解释了不同类型的测试双打及其目的。

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

显然值得补充的是,测试设计在这里很重要,但请记住,尽管90%的IoC / mocking / DIP示例显示interface-implementation pairs(ICustomerRepository / CustomerRepository),但在寻找中有很多价值role interfaces

答案 1 :(得分:3)

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

答案 2 :(得分:3)

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

答案 3 :(得分:1)

当使用服务时,无论是我自己的服务还是第三方服务,我都设计了接口,因此我倾向于关注那里的交互。这鼓励我设计最小的接口。

我检查关于值对象的任何事情的状态,就像简单的计算,查找等一样。

下次当你发现自己设计的东西通常遵循Model / View / Controller-or-Presenter时,我强烈建议使用Model和View的界面来尝试Presenter First方法(Google it)。这将使您对如何有效地使用存根/模拟有一个很好的感觉。

答案 4 :(得分:0)

它的风格问题...... Mockist vs Classic TDDers 就个人而言......我会尽可能地去测试真正的课程。尽可能地减少对模拟的影响;只是为了解决诸如IO(文件系统,数据库连接,网络),第三方组件等的事情,这些事情很慢/很难被测试。

答案 5 :(得分:0)

作为一名经验丰富的TDD,这是我经常被其他开发人员问过的问题。对我来说,被嘲弄Mockist vs. Classicist辩论是错误的,因为这样的讨论会产生误导。基于状态和基于行为的单元测试是工具箱中的两个不同工具,没有理由说它们应该是互斥的。

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

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

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