【发布时间】:2017-12-28 10:32:26
【问题描述】:
我一直在使用 Symfony 开发我的 Web 应用程序,但我一直遇到一个问题。由于我希望能够正确地对我的服务进行单元测试,因此我的服务构造函数总是过于混乱。
理论用例
假设我需要一个服务,它允许我处理 XML 文件并将其内容保存到数据库中。
<?xml version="1.0" encoding="UTF-8" ?>
<users>
<user>
<id>1234</id>
<username>Example User</username>
<email>user@example.com</email>
<usergroup>
<id>567</id>
<name>Example User Group</name>
</usergroup>
<permissions>
<item>ALLOWED_TO_CREATE</item>
<item>ALLOWED_TO_UPDATE</item>
<item>ALLOWED_TO_DELETE</item>
<item>ALLOWED_TO_view</item>
</permissions>
</user>
</users>
您已经想到了很多需要注入此服务的东西:
- DomCrawler(读取 XML 文件)
- UserRepository(获取现有用户)
- UserGroupRepository(获取现有用户组)
- PermissionsRepository(获取现有权限)
- EntityManager(保持刷新新/更新的对象)
我正在使用的真实 XML 文件包含更多数据,这需要我注入更多存储库和其他处理某些逻辑的服务。
解决方案 1:使用 Doctrine 服务
将 Doctrine 服务目录注入到我的服务中,并通过 $doctrine->getRepository(User::class) 获取存储库
优点
- 显着减少参数数量
缺点
- 单元测试变得更加困难,因为我不知道服务访问什么,这使得它们变得无用
解决方案 2:使用 setter 注入
从构造函数中删除所有服务和存储库并创建setter方法,然后在services.yml中调用
services:
AppBundle\Service\MyImportService:
calls:
- [setUserRepository, ['@app.user_repository']]
优点
- 可以说更容易阅读
缺点
- 更多代码
- 服务不再是强制性的,可能需要可选的验证
问题
有哪些解决方案可以使我的服务中的参数列表在可读性和单元测试能力方面更易于维护?
一长串论据甚至被认为是不好的做法吗?
【问题讨论】:
-
考虑例如将 UserRespository、UserGroupRepository 和 PermissionRepository 组合到某种 UserFinder 服务中。对于您注入的所有单个服务,如果您认为自己正在进行适当的单元测试,我认为您可能是在自欺欺人。一个技巧是将持久化/刷新添加到您的存储库中,这通常避免了直接与实体管理器打交道的需要。
-
可能还会从域驱动设计人员那里了解聚合根的概念。现在你的脑海里有一个印象,User UserGroup 和 Permission 都是单独的对象,但事实上,在这个特定的设计环境中,你真正拥有的只是一个更复杂的用户对象。
标签: php symfony unit-testing dependency-injection