如何将 TDD 应用于逐层封装设计?
How to apply TDD to a package-by-layer design?
我已经阅读了很多关于 TDD 的文章,尤其是关于各种实践和经验、该做和不该做的,在尝试将它应用到 Spring 引导后我仍然对几个方面感到困惑具有持久性和 REST 的应用程序,全部按功能打包。
Whosebug 上的许多博客文章和答案都建议我们应该测试接口而不是实现。
但是,例如史蒂夫·弗里曼和纳特·普赖斯 "Growing Object-Oriented Software, Guided by Tests" 中的例子,提出了一种完全不同的方法,
因为他们都主要测试实现,断言方法调用的数量等。所以我们的测试实际上变得依赖于实现本身。
当然,我们可以使用控制反转 - 通过构造函数传递依赖项并在我们的测试中模拟它们,但是模拟真的有意义吗,比方说,一个 CRUD 存储库?
也许我会给你一个简单的例子来更好地描述这种情况。
假设我们有一个多页的用户信息表单,每个表单页面都必须单独保存。
因此,信息包的计划结构可能是这样的,按照按功能包的方法:
com
.. example
.... user
...... information
........ basic
.......... + BasicInformationDto
.......... + BasicInformationService
.......... - BasicInformationServiceImpl
.......... - BasicInformationDao
.......... - BasicInformationRepository
........ additional
.......... + AdditionalInformationDto
.......... + AdditionalInformationService
.......... - AdditionalInformationServiceImpl
.......... - AdditionalInformationDao
.......... - AdditionalInformationRepository
........ + InformationRestController
+ is public and - is default access modifier
我的第一个想法:
- 编写一个简单的 REST 集成测试来测试由
InformationRestController.
- 用这些创建 InformationRestController
映射。
- 为 BasicInformationService 创建测试,创建一个
BasicInformationServiceImpl 对象,模拟 BasicInformationRepository
并测试存储库的保存方法是否被恰好调用一次。
- 为 BasicInformationService 创建 类,
BasicInformationServiceImpl 和 BasicInformationRepository 与
基本信息道。
- 重构,实现细节,dto和dao
字段等
如果我以后决定使用存储库的#saveAndFlush 怎么办?一个单元测试因为这么小的改动就需要重构,这正常吗?
如果我只测试接口,我该如何测试具有不同依赖项的不同实现?
那么,如果 BasicInformationService 的保存方法仅将 DTO 对象映射到 DAO,然后使用 BasicInformationRepository 持久化它,那么如何使用 TDD 设计 BasicInformationService 的保存方法?
简而言之,BDD(行为驱动开发)是 TDD 的一种改进,从测试整个堆栈的验收测试开始,然后根据需要通过单元测试来测试驱动细节。 You can unit-test every class if you want, but you don't have to, and I don't where it doesn't add value. 在你给出的情况下,我怀疑不需要对大多数组件进行单元测试。
在执行 TDD/BDD 时以已知设计为目标是完全正常的,因为您的框架需要它,或者因为该设计已经在您程序的其他垂直部分中建立。只有最极端的 TDD 开发者才会在没有框架的情况下开始。您不想做的是构建一个您的框架 不需要 并且测试和重构还没有告诉您您需要的大型设计。
我已经阅读了很多关于 TDD 的文章,尤其是关于各种实践和经验、该做和不该做的,在尝试将它应用到 Spring 引导后我仍然对几个方面感到困惑具有持久性和 REST 的应用程序,全部按功能打包。
Whosebug 上的许多博客文章和答案都建议我们应该测试接口而不是实现。 但是,例如史蒂夫·弗里曼和纳特·普赖斯 "Growing Object-Oriented Software, Guided by Tests" 中的例子,提出了一种完全不同的方法, 因为他们都主要测试实现,断言方法调用的数量等。所以我们的测试实际上变得依赖于实现本身。 当然,我们可以使用控制反转 - 通过构造函数传递依赖项并在我们的测试中模拟它们,但是模拟真的有意义吗,比方说,一个 CRUD 存储库?
也许我会给你一个简单的例子来更好地描述这种情况。 假设我们有一个多页的用户信息表单,每个表单页面都必须单独保存。
因此,信息包的计划结构可能是这样的,按照按功能包的方法:
com
.. example
.... user
...... information
........ basic
.......... + BasicInformationDto
.......... + BasicInformationService
.......... - BasicInformationServiceImpl
.......... - BasicInformationDao
.......... - BasicInformationRepository
........ additional
.......... + AdditionalInformationDto
.......... + AdditionalInformationService
.......... - AdditionalInformationServiceImpl
.......... - AdditionalInformationDao
.......... - AdditionalInformationRepository
........ + InformationRestController
+ is public and - is default access modifier
我的第一个想法:
- 编写一个简单的 REST 集成测试来测试由 InformationRestController.
- 用这些创建 InformationRestController 映射。
- 为 BasicInformationService 创建测试,创建一个 BasicInformationServiceImpl 对象,模拟 BasicInformationRepository 并测试存储库的保存方法是否被恰好调用一次。
- 为 BasicInformationService 创建 类, BasicInformationServiceImpl 和 BasicInformationRepository 与 基本信息道。
- 重构,实现细节,dto和dao 字段等
如果我以后决定使用存储库的#saveAndFlush 怎么办?一个单元测试因为这么小的改动就需要重构,这正常吗? 如果我只测试接口,我该如何测试具有不同依赖项的不同实现?
那么,如果 BasicInformationService 的保存方法仅将 DTO 对象映射到 DAO,然后使用 BasicInformationRepository 持久化它,那么如何使用 TDD 设计 BasicInformationService 的保存方法?
简而言之,BDD(行为驱动开发)是 TDD 的一种改进,从测试整个堆栈的验收测试开始,然后根据需要通过单元测试来测试驱动细节。 You can unit-test every class if you want, but you don't have to, and I don't where it doesn't add value. 在你给出的情况下,我怀疑不需要对大多数组件进行单元测试。
在执行 TDD/BDD 时以已知设计为目标是完全正常的,因为您的框架需要它,或者因为该设计已经在您程序的其他垂直部分中建立。只有最极端的 TDD 开发者才会在没有框架的情况下开始。您不想做的是构建一个您的框架 不需要 并且测试和重构还没有告诉您您需要的大型设计。