【发布时间】:2016-11-18 00:16:16
【问题描述】:
我对 Java 还很陌生,并且加入了一个利用 DDD 模式的项目(据说)。我来自强大的 Python 背景,并且对单元测试驱动设计非常了解。也就是说,迁移到 Java 的挑战之一是服务层的可测试性。
我们的类 REST 项目堆栈布局如下:
-
ServiceHandlers处理请求/响应等并调用IService的特定实现(例如DocumentService) -
DocumentService- 使用makeOwner(session, user, doc)等方法处理审计、权限检查等
目前,DocumentService 之类的东西通过 guice 注入了存储库依赖项。在像DocumentService.makeOwner 这样的公共方法中,我们希望确保会话用户是管理员,并检查目标用户是否已经是所有者(利用注入的存储库)。这会导致一些重复代码 - 一个用于解决用户并确保成员资格、权限等的两个用户的代码。为了消除这种冗余代码,我想做一种超级简单的isOwner(user, doc) 调用,我可以简洁地模拟出来各种测试场景(如无法解析用户时抛出异常等)。这是我的谷歌搜索失败的地方。
如果我把它和DocumentService 放在同一个类中,我不能在同一个类中测试makeOwner 时模拟它(由于 Mockito 的限制),即使它有点感觉应该放在这里(选项 1) .
如果我把它放在像DocumentHelpers 这样的低级,感觉有点好笑,但我可以很容易地嘲笑它。此外,DocumentHelpers 也需要注入的存储库,这对 guice 来说很好。 (选项 2)
我应该补充一点,在我们的婴儿代码库中有许多这种性质的点目前是不可测试的,因为方法是在同一个 *Service 类中非静态调用类似帮助器的方法,而上层 ServiceHandler 类没有使用。但是,在这个阶段,我无法判断这是糟糕的设计还是很好。
所以我询问了更有经验的 Java 开发人员:
- 引入“服务助手”似乎是一个有效的解决方案?
- 这是否与 DDD 主体相反?
- 如果没有,除了“Helpers”之外,是否还有更多对 DDD 友好的命名约定?
要添加 3 位:
- 我的谷歌搜索主要是关于“助手”作为无状态操作(如日期格式)的静态实用方法的争论,这不符合我的问题。
- 我不想使用 PowerMock,因为它会破坏代码覆盖率并且使用起来非常难看。
- 在 python 中,我可能将上述“服务助手”层称为 internal_api,但这在 Java 中似乎有不同的含义,尤其是因为我需要公开这些类来对它们进行单元测试。
感谢任何指导。
【问题讨论】:
-
文档所有者始终是管理员是否重要,或者它只是一个初始的先决条件?
-
这是一个有点武断的案例,但重新阅读它实际上意味着我们需要检查目标用户是否已经是所有者,而不是管理员。但一般来说,在此示例中,只有管理员可以提升/降级文档所有者。好消息,我会更新的。
-
我觉得这里唯一的问题是
DocumentService的责任太大了。您的域是关于文档的,但是拥有DocumentService就像是代码异味。您可能有一个负责移交所有权的DocumentHandlingService,您还可能有一个DocumentPermissionService和一个DocumentAuditingService。您可能希望从这些服务名称中删除Document。
标签: java unit-testing design-patterns mockito domain-driven-design