【发布时间】:2021-12-05 21:10:17
【问题描述】:
备注:
- 我使用术语 mocking 作为通用术语,意思是所有类型的测试替代品,包括间谍、伪造品、模拟、存根和所有其他东西。
- 在写我的问题时,我只谈到了干净架构中的“用例”,但我的问题还涉及 DDD 中的“域服务”。
我们走吧:
我目前正在尝试在一个新项目中实施 DDD 和清洁架构原则。但是,我已经坚持了 1 周 ---> 如何为我的用例编写单元测试
这是我的问题:
在 Clean Architecture 中,当我们创建一个用例(或 DDD 中的域服务)时,它在大多数情况下将取决于一定数量的实体 + 其余部分(存储库、api ...)
要编写我的用例的单元测试,我从以下内容开始:
- 模拟与外部交互的“其余”依赖项(存储库、API ...)
- 但是接下来,我应该如何处理单元测试中的实体依赖项?
以下是我想到的解决方案:
- 解决方案 1: 我在注入虚假实体
- 但是,通过阅读有关单元测试最佳实践的内容,我了解到我们应该尽可能避免创建模拟,因为它们是“代码味道”,而一个好的设计应该可以不用它们。
- 事实上,嘲笑我的实体意味着我削弱了我的测试。测试将与我的模拟实体紧密耦合。
- 此外,重新创建实体的结构对我来说似乎毫无意义......
* 如果我的用例使用多个实体方法:那么我必须重新创建每个方法的返回值。
* 如果我的实体的结构很复杂,我最终会写出复杂的假货,因此我的测试会失去很多可靠性,而且我的假货更有可能是错误的,而不是我原来的实体)
* 更糟糕的是,如果我使用工厂,那么我将不得不制造工厂的假货 -> 假货将不得不建立一个假实体......
- 解决方案 2: 我不模拟实体。
- 另一方面,如果我不模拟我的实体,那么我认为我会采用集成测试的方式:测试不同实体之间的交互...
- 也正如一些模拟支持者所指定的:如果我不模拟我的依赖项,那么即使我的测试单元是有效的,如果我的依赖项导致错误,测试也会失败。这将在我的测试中导致错误的警报信号...
- 解决方案 3:重构生产代码
- 通过阅读几篇文章,一些人提供了限制耦合的解决方案(将副作用与其余逻辑隔离,将逻辑与 I/O 隔离,使用纯函数,依赖注入,...)但即使通过应用所有这一切,一个用例将不可避免地需要这些实体来工作......因此它不是一个解决方案。
但是那怎么办呢?我错过了什么吗?
如何对用例(或 DDD 中的服务域)进行 GOOD 单元测试? : 在单元测试中有实体依赖的单元测试中如何管理实体?
示例:
为了说明我的问题并更好地理解您的答案,这里是一个虚构的问题示例:
假设我有以下实体:
+class HorseEntity()
+constructor(name,age,health, ...)
+equipSaddle()
+makeShoeing()
+checkHealth()
我想创建一个用例来为我的马厩添加一匹马:
+class addHorseUseCase()
+execute(requestDto,HorseRepo,HorseEntity, ...)
这个用例是:
- 创建马实体
- 检查马的健康状况
- 给马穿鞋
- 为马配备鞍
- 并将其添加到马厩中。
当我创建测试时,我应该如何处理“HorseEntity”依赖项?
我的问题总结:
- 如何为一个用例编写一个好的单元测试以及如何在我的测试中处理实体依赖关系?
- 一般来说,我应该如何处理单元测试中的实体依赖项?
- 在上面这个例子中,如何为“addHorseUseCase”编写一个好的单元测试?
感谢您以后的回答。
PS:我将这个问题从法语翻译成英语,如果您不理解我的其中一个句子的措辞,请随时告诉我,以便我进行编辑。
【问题讨论】:
标签: unit-testing architecture domain-driven-design clean-architecture