【问题标题】:Unit Testable convention for Service "Helper Classes" in DDD patternDDD 模式中服务“助手类”的单元可测试约定
【发布时间】: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 开发人员:

  1. 引入“服务助手”似乎是一个有效的解决方案?
  2. 这是否与 DDD 主体相反?
  3. 如果没有,除了“Helpers”之外,是否还有更多对 DDD 友好的命名约定?

要添加 3 位:

  • 我的谷歌搜索主要是关于“助手”作为无状态操作(如日期格式)的静态实用方法的争论,这不符合我的问题。
  • 我不想使用 PowerMock,因为它会破坏代码覆盖率并且使用起来非常难看。
  • 在 python 中,我可能将上述“服务助手”层称为 internal_api,但这在 Java 中似乎有不同的含义,尤其是因为我需要公开这些类来对它们进行单元测试。

感谢任何指导。

【问题讨论】:

  • 文档所有者始终是管理员是否重要,或者它只是一个初始的先决条件?
  • 这是一个有点武断的案例,但重新阅读它实际上意味着我们需要检查目标用户是否已经是所有者,而不是管理员。但一般来说,在此示例中,只有管理员可以提升/降级文档所有者。好消息,我会更新的。
  • 我觉得这里唯一的问题是DocumentService的责任太大了。您的域是关于文档的,但是拥有DocumentService 就像是代码异味。您可能有一个负责移交所有权的DocumentHandlingService,您还可能有一个DocumentPermissionService 和一个DocumentAuditingService。您可能希望从这些服务名称中删除 Document

标签: java unit-testing design-patterns mockito domain-driven-design


【解决方案1】:

启动操作的用户必须是管理员,这看起来像是应用程序级别的访问控制问题。 DDD 对您应该如何做到这一点没有太多意见。出于可测试性和关注点分离的目的,拥有某种单独的非静态类可能比同一服务中的方法或静态助手更好。

检查未来的所有者是否已经是所有者(如果我理解正确的话)可能是另一种动物。它可能是您域中的不变量。如果是这样,首选方法是依靠聚合来执行该规则。但是,从您的描述中不清楚 Document 是否是一个聚合,以及它或另一个聚合是否包含判断用户是否为所有者所需的数据。

或者,您可以在应用层级别验证规则,但这意味着如果状态更改是由该应用层之外的其他东西触发的,您的域模型可能会不一致。

【讨论】:

    【解决方案2】:

    随着我对 DDD 的了解越来越多,我的问题似乎与 DDD 无关,更多的是关于代码结构的一般层次结构和各层的交互。我们最终使用了一个可以模拟出来的单独的 DocumentServiceHelpers 类。这包含像 isOwner 这样的方法,我们可以根据需要模拟返回 true 或 false 以更轻松地测试我们的 DocumentService 处理。感谢大家一起玩。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-15
      • 1970-01-01
      • 2021-02-06
      • 2011-05-05
      • 1970-01-01
      • 2012-03-24
      相关资源
      最近更新 更多