Unit testing 在交互者/用例/应用程序服务中违反Demeter法

Unit testing 在交互者/用例/应用程序服务中违反Demeter法,unit-testing,oop,domain-driven-design,use-case,Unit Testing,Oop,Domain Driven Design,Use Case,最近我一直在研究一系列关于软件架构的想法。我所看到的是,它们中的许多都汇聚到使用用例/交互器(干净的体系结构)或应用程序服务(DDD)作为我们应用程序的入口点 我真的很喜欢这个主意,但有些事情一直困扰着我 用户注入存储库的两种方式,您使用存储库获取域实体并对其执行操作。像这样: class Interactor def initialize(repository) @repository = repository end def call(entity_id) en

最近我一直在研究一系列关于软件架构的想法。我所看到的是,它们中的许多都汇聚到使用用例/交互器(干净的体系结构)或应用程序服务(DDD)作为我们应用程序的入口点

我真的很喜欢这个主意,但有些事情一直困扰着我

用户注入存储库的两种方式,您使用存储库获取域实体并对其执行操作。像这样:

class Interactor
  def initialize(repository)
    @repository = repository
  end

  def call(entity_id)
    entity = @repository.find(entity_id)
    entity.do_something
  end
end
如果我想单独测试这个,我需要从
@repository.find
返回一个mock,它已经是一个mock了。这是不好的,告诉我我违反了德米特法(事实就是这样)

而且,这太程序化了,这让我很困扰

有更好的方法吗

这是不好的,告诉我我违反了德米特法(事实就是这样)

怎么会这样

Demeter定律以多种方式进行了总结和解释,但为了简单起见,让我们看看下面的小列表:

  • 每个单元对其他单元的了解应有限:仅与当前单元“密切”相关的单元
  • 每个单位只能和朋友交谈;不要和陌生人说话
  • 只和你的直系朋友交谈
那么,显示的代码在哪些方面违反了这项法律<代码>交互者只知道两件事,一个特定的存储库和一个特定的实体。它对存储库的了解是一个技术问题,它使用这种交互来获取实体的实例。它对实体的了解是一个业务关注点,它使用这种交互来执行业务操作

在任何域图形、图表或白板绘图上,
interactitor
都应与这两个单元直接连接。确实如此。它进入这些单位并不是为了了解他们的邻居,它只是了解自己的邻居,并且只与他们互动

所以。。。到底是什么问题

作为纯粹的技术问题,您可以直接注入实体,而不是注入存储库。没有足够的关于问题中所代表的系统的信息来真正列出任何优点和缺点。但这不是德米特定律的问题,这只是依赖关系管理的实现问题

当然,单元测试需要创建两个模拟。但是这个单元与两个单元交互。所以这是一个给定的,真的

这是不好的,告诉我我违反了德米特法(事实就是这样)

怎么会这样

Demeter定律以多种方式进行了总结和解释,但为了简单起见,让我们看看下面的小列表:

  • 每个单元对其他单元的了解应有限:仅与当前单元“密切”相关的单元
  • 每个单位只能和朋友交谈;不要和陌生人说话
  • 只和你的直系朋友交谈
那么,显示的代码在哪些方面违反了这项法律<代码>交互者只知道两件事,一个特定的存储库和一个特定的实体。它对存储库的了解是一个技术问题,它使用这种交互来获取实体的实例。它对实体的了解是一个业务关注点,它使用这种交互来执行业务操作

在任何域图形、图表或白板绘图上,
interactitor
都应与这两个单元直接连接。确实如此。它进入这些单位并不是为了了解他们的邻居,它只是了解自己的邻居,并且只与他们互动

所以。。。到底是什么问题

作为纯粹的技术问题,您可以直接注入实体,而不是注入存储库。没有足够的关于问题中所代表的系统的信息来真正列出任何优点和缺点。但这不是德米特定律的问题,这只是依赖关系管理的实现问题


当然,单元测试需要创建两个模拟。但是这个单元与两个单元交互。所以这是一个给定的,真的。

交互者
没有实体的知识。我不是直接在它上面注射实体。我可以很容易地将我的代码替换为
@repository.find(entity\u id)。dou\u something
,这样我就可以清楚地知道我违反了Demeter。我举了一个抽象的例子,因为这样的事情一直在发生(除了我创造实体的时候)。@Thiago:我认为这是对法律条文的过度解读,而忽视了法律的意图。该意图可以在域的白板图上演示。如果A和B是连接的,那么A可以与B交互。A从C获得B的实例并不重要。A也可以很容易地创建B的实例,但由于不相关的原因,B是由工厂创建的,而不是直接实例化的。@Thiago有什么难测试的?里面只有一个模子。。。存储库。我希望你不是在嘲笑域对象,是吗?@Thiago不,你不是。如果不是域逻辑,您想测试什么?由于有太多的模拟,您将不得不为您的测试编写测试;)为什么要模拟域对象?因为我的目的是对每个组件进行单元测试。域对象将有自己的测试。
interactitor
没有实体的知识。我不是直接在它上面注射实体。我可以很容易地将我的代码替换为
@repository.find(entity\u id)。dou\u something
,这样我就可以清楚地知道我违反了Demeter。我做了一个抽象的例子,因为这样的事情一直在发生(除了我创建实体的时候)。@Thiago:我认为这是对let的过度解读