.NET Core TDD 前传: 编写易于测试的代码 -- 依赖项

第1篇: 讲述了如何创造"缝".  "缝"(seam)是须要知道的概念.html

第2篇, 避免在构建对象时写出不易测试的代码.函数

本文是第3篇, 讲述依赖项和迪米特法则.测试

 

迪米特法则 (Law of Demeter)

仍是使用建造汽车的例子. 生产汽车的时候须要轮胎, 组装时须要什么型号的轮胎, 就请求该型号的轮胎, 而后相关人员会从库房把该型号的轮胎送到产线用于组装. spa

我相信不多有汽车厂会这样作: 生产汽车时, 汽车组装工拿着库房的钥匙, 本身去库房从各类各样的轮胎中找所须要的型号..htm

这就是违反迪米特法则的一个例子.对象

 

迪米特法则大概的意思是: "只访问你本身建立的对象, 或者做为参数传给你的对象. 不要经过其它对象间接的访问对象"blog

用一句话概括迪米特法则就是: "只与直系朋友交谈, 不要和陌生人交谈".接口

 

注意: 迪米特法则其实并不算严格的法则, 它只是一个很是有益的指导性原则. get

 

存在的问题

用代码形容上面的例子就是: 容器

这违反了迪米特法则, 致使了如下问题:

  • 形成了BenzCar和Warehouse以及MichelinTire之间的紧耦合, 而实际上BenzCar只须要MichelinTire.
  • 测试时, 设置会很麻烦. 代码里Warehouse是直系朋友, MichelinTire是陌生人. 咱们须要为Warehouse和MichelinTire同时设置测试替身.
  • 真正须要的依赖项没有明确在构造函数里定义. 这里Warehouse至关因而一个容器, 测试时, 咱们可能会不知道要为Warehouse里的哪一个东西作测试替身.

 

危险信号

下列写法可能意味着您的代码违反了迪米特法则:

  • 代码里有这样的调用: "warehouse.getTire.getMichelinTire", 有一连串的点".". 可是有时候这样作是能够的, 例如流畅(fluent)形式的建造者模式就能够, 由于fluent接口一般会返回对象自己, 而后再去使用该对象.
  • 依赖于容器. 例如把 IocContainer做为依赖注入使用. 
  • 依赖项的名称为XxxContext, XxxContainer, XxxEnvironment, XxxManager, XxxServiceLocator.
  • 测试时须要建立返回mocks的mock对象.
  • 测试时的设置很是麻烦.

 

解决办法

解决办法就是听从迪米特法则.

只注入咱们直接须要的依赖项, 直接使用它们. 这样就会保证依赖项很明确, 测试的时候一眼就能看出依赖于哪些对象.

代码示例

例子一

下面这个违反了迪米特法则, 直接注入的是Warehouse, 而实际用到的倒是MichelinTire:

 

正确的作法是, 注入直接使用的依赖项:

 

例子二

下面的代码也违反了迪米特法则, 它注入了一个容器类的对象:

这个ServiceLocator就至关因而一个容器. 这样用的话, 写测试的人可能根本没法知道须要使用容器里面的哪一个对象.

你也许会说这样作灵活(我之前也常常这样作), 可是重构的时候, 这里很容易出错, 由于根本看不出来真正依赖的是哪一个对象.

 

正确的作法仍是应该注入直接须要的依赖项:

 

Law of Demeter相关的内容就简单介绍这些.

相关文章
相关标签/搜索