zoukankan      html  css  js  c++  java
  • 【转载】 单元测试:是否针对非 public method 进行测试?

    前言

    在VisualStudio的单元测试中,对于非public的函数,可以通过VisualSTudio自动产生accessor来进行测试。但 Visual Studio 2012却把这个功能给移除了,让不少开发者感到不便。本篇文章就来说明,单元测试是否应该对测试物件非 public 的部份,进行单元测试。

     

    单元测试的意义

    一言以蔽之,「单元测试就是用来模拟外部如何使用测试目标物件,验证其行为是否符合预期」。

    因此,有个重点是:外部如何使用测试目标物件。

    让我们回到 Object-Oriented 的封装原则,封装的用意在于:

    1. 隔离出物件的内部与外部。也就是定义「物件的边界」,以及定义「外部可视部分」。
    2. 将外部使用端,不需要了解物件的内部资讯,封装起来。也就是「封装细节」。
    3. 将物件内部的变化,封装起来。也就是「封装变化」。

    有了对单元测试与封装的认知后,接下来说明,为什麽单元测试只需要针对测试目标物件 public 的行为,进行测试即可。为什麽 Visual Studio 2012 要把 accessor 的功能移除。(不过这纯属我自己从单元测试意义当出发点的推论)

     

    只测试 Public 行为?

    根据单元测试的意义,以及封装的用意,代表着「外部使用者原本就不需要了解,也根本不了解,测试目标物件非public的行为」。单元测试既然是模拟外部使用端的动作,那当然只针对测试目标物件 public 的行为进行模拟与验证。

    但一些朋友肯定有些疑惑,那非 public 的 method 该怎麽办?不测吗?那 code coverage 怎麽提升?要怎麽知道这些非 public 的行为有没如同预期般运作呢?

    有这些疑问是正常的,因为我一开始也是有一模一样的疑问,但开始接触 TDD 之后,反而更加了解了 Unit Test 的本质。

    所谓的非 public 的行为,其存在的原因,一定是因为某一些 public 的行为会用到这些 private 或 protected 的 method,如果物件中存在着跟 public method 无关的 private 或 protected method,那在设计上就是个问题,这些非 public 的 method 根本就没有存在的意义。因为外部使用测试目标物件时,完全不会用到这些 method,就像宣告了变数却不去使用它一样,没有意义

    而当 private 或 protected method 与 public method有关时,那针对 public method 的 Unit Test 便会涵盖到这些 private 或 protected method,它们就是 public method 的一部分,对外部使用者来说,根本分辨不出来什麽是 private 或 protected,因为只关注在物件外部可视行为上。

    所以,在实作单元测试上,倘若测试物件一个 public method 中,涵盖了一个 private method,而 private method 中与外部物件或服务相依,那麽在测这个 public method 时,要连 private method 中相依的 interface ,都要撰写 stub object 来模拟才行,这也是为什麽单元测试被称为白箱测试的原因。但还是得强调一次,外部使用者是无法分清楚哪一部分是 public method 内容,哪一部分是非 public method。

    总结上面的说法,非 public method 的测试涵盖率,是依据 public method 呼叫时的 input 来决定。

    有没有可能,当 public method 该测的都测了,甚至 public method 主体内容涵盖率都 100% 了,非 public 的部分涵盖率却很低?当然有可能,但这要釐清一下,没有被涵盖到的部份,是属于什麽样的程式码。

    如果在非 public method 中,没被测试覆盖的部份,是防呆、断言之类的程式码,那麽是属于正常的情况。因为可能在呼叫非 public method 之前,就已经先防呆了,导致非 public method 中的防呆永远不会发生。但,因为系统的健壮性考量,该断言、防呆、验证的部份,还是不能少。因为不会知道未来其他方法呼叫前,有没做好防呆的部份。

    那麽,在 private 或 protected method 中,非防呆、断言的程式码,却又没被涵盖到部分呢?这是个警讯,代表着这些程式码可能是 over design,或是根本没有用处。因为这个物件所有对外的行为,所有的可能性,都模拟过一次了,却都不会用到这些没被涵盖到的程式码,这不就代表「这些程式码目前用不到」吗?YAGNI 原则就是在说这件事:「You ain't gonna need it !」

    只要 public 的行为如同预期,即使 private 或 protected 的 method 是 hard-code,是很没弹性,是很愚蠢的写法,对外部使用来说,根本就不在乎,因为无感。

    这也是 TDD 所提倡的精神,如果所有使用行为都符合预期,就代表功能完成了。而且依据测试来撰写的 production code,几乎不会出现测试涵盖不到的 code,因为 production code 是为了满足测试而撰写的。不需要存在用不到的 production code,因此,也可以避免 over design 的情况。

     

    针对非 public 行为测试又如何?

    上面那一段的说明,肯定还是无法说服所有人,「为什麽要把已经存在的功能移除?」

    不用 accessor 的人大可不用,但已经在用,或真的得用的人,还是希望可以在 VS2012 中继续使用。

    回到封装的用意上,「封装变化」一直是面向对象设计中很重要的设计原则。那些针对 private 与 protected 进行单元测试的朋友,有没有过「因为一些需求异动,导致单元测试程式就需要跟着重新调整、设计或修改,而且频率与范围导致测试的维护成本增加不少」的经验。如果有,这就是为什麽不希望 developer 去针对非 public method 写单元测试的原因。

    着重在非 public method 的单元测试,说穿了只是写给 developer 爽而已。因为要封装变化,才会把这些内容变成 private 或 protected,以期望变化时对外部使用者来说,呈现无感,也就是降低耦合,也就是最小知识原则。

    现在单元测试却透过某些机制,来存取这些封装起来的行为,不是自讨苦吃吗?原本就知道,这些东西很可能会一直变化,却又去存取它,测试它,导致单元测试因此维护与异动频率增加,这不就违背了封装的用意?对使用来说,根本不关心这些变化,却因为单元测试用髒方法硬干到这些不公开的行为,导致测试成本增加,进而导致一些不明就裡的 developer 喊出「测试很花成本,时间增加很多,很难维护」。我只想说:「这不是南北拳的问题,是你的问题。」

     

    结论

    说真的,刚知道 Visual Studio 2012 把 accessor 功能拿掉,我也一整个相当吃惊,觉得要强迫 developer 用 TDD 方式开发,也不用做到这麽绝吧。

    但将面向对象的原则、TDD 的精神、单元测试的基本意义结合起来后,有了上述的思考历程,就觉得只测试 public method,不建议测试 private 与 protected method,是一件正确且重要的事。

    所以将这样的思考与推论过程,分享给各位朋友参考,不一定完全符合 Visual Studio 2012 移除 accessor 的原因,这只是我自己的理解与想法而已,但从我一开始接触单元测试,怎麽测 private method 就一直困扰我很久,虽说脑袋中有点轮廓,却一直无法明确釐清。

    可以的话,后面几篇文章,会再针对 production code 的可测试性,来说明如何透过单元测试以及程式码的可测试性,来检验与提昇程式码的品质。

     

    原文请访问:http://www.dotblogs.com.tw/hatelove/archive/2012/07/19/why-you-should-not-write-unit-test-with-private-and-protected-method.aspx


  • 相关阅读:
    XAML学习笔记之Layout(五)——ViewBox
    XAML学习笔记——Layout(三)
    XAML学习笔记——Layout(二)
    XAML学习笔记——Layout(一)
    从0开始搭建SQL Server 2012 AlwaysOn 第三篇(安装数据,配置AlwaysOn)
    从0开始搭建SQL Server 2012 AlwaysOn 第二篇(配置故障转移集群)
    从0开始搭建SQL Server 2012 AlwaysOn 第一篇(AD域与DNS)
    Sql Server 2012 事务复制遇到的问题及解决方式
    Sql Server 2008R2升级 Sql Server 2012 问题
    第一次ACM
  • 原文地址:https://www.cnblogs.com/TianFang/p/2602121.html
Copyright © 2011-2022 走看看