InfoQ

InfoQ

新闻

我的书签

登录注册 以永久保存书签。

该内容已经被标记书签!

标记书签错误,请重试!

私有方法、测试驱动开发与优秀设计

作者 Amr Elssamadisy 译者 李剑 发布于 2008年1月8日

领域
架构 & 设计,
过程 & 实践,
语言 & 开发
主题
单元测试 ,
敏捷 ,
面向对象设计
标签
测试驱动开发
有人说“TDD(测试驱动开发)可以带来优秀的设计”,也有人说“TDD会对设计有负面影响”。如果有个具体例子的话,讨论起来会实际得多,所以下面我们来看一下私有方法以及它与优秀设计、可测试性的关系——这种对立观点的一个实例。

Szczepan Faber在博客中写道,私有方法是一种反模式

自从TDD诞生之日起,私有方法似乎就有了坏味道。被测试浸染的开发者总想寻找测试私有方法的办法。嗯……这显然是很困难的,所以问题就从“如何”变成了“为何”:为何要测试私有方法?大多数TDDers都会立刻回答说:别这么干。于是TDD又改变了我们构建软件的方式,对私有方法进行了重新评估 :)

Jay Fields在博客上描述了在ruby中测试私有方法的一种通用方式

……我很少测试私有方法。我更倾向于通过public API来进行测试。不过偶尔也有这种时候,如果你可以给一两个私有方法写点测试用例的话,日子就可以过的容易一些。

Michael Feathers在去年的The Deep Synergy Between Testability and Good Design一文中指出,TDD可以带来优秀的设计,而反过来想,那些不可测试的代码应该引起我们的深思:

在我编写测试时,如果觉得有强烈的冲动促使我去测试一个私有方法,我就会把它看作一种暗示。它告诉我,我的类已经被封装得趋近于封闭了,测试代码无法再通过公共接口来“理解”这个类的行为。我顺从了这个暗示的召唤,重新构建了代码。通常我都会把这个私有方法(可能还有一些相关的方法)挪到一个新的类里面,在那里它不再是私有,可以让测试代码访问。

以上种种想法,都倾向于不鼓励使用私有方法,在天平的可测试性一端加入更多砝码。但它们并不是唯一的声音。实际上在我们所能看到的有关面向对象开发的观点中,很多都是支持少用一些类,极尽所能使用封装。在public API中只暴露最小的API集合,就会将耦合降低到最小。David West在Object Thinking一书中,引用了Lorenz和Kidd在Object Oriented Software Metrics书中的论述:

  • 一个应用程序应该最多包括40个故事,100个类。
  • 应用程序所属的整个业务领域不应该需要超过1000个类来完成。
  • 每一次迭代后都该扔掉25-30%的代码。
  • 每个类的职责:平均是7个。
  • 每个类的方法数:平均是12个。
  • 每个方法的代码行数:平均是15个。
  • 需要进行注释的代码行数百分比:60。
  • case语句的数量:平均为0。

如果私有方法确实是坏味道,需要把它们挪到自己所应归属的类中,这不就是“为了让测试变得简单,而增加类的数量”么?它势必会造成类的数量急剧膨胀。

那么该拿私有方法怎么办呢?测试它们太折磨人了。我们可否修改一下,把它们暴露给测试代码?或者不去测试私有方法,让设计与可测试性永不相干?或者,私有方法是一种坏味道,它表明一个类做了太多事情?

查看英文原文Private Methods, Test Driven Development, and Good Design

译者 李剑 李剑──ThoughtWorks高级咨询师,在持续集成、重构等领域具有丰富的经验;多次为国内大型企业敏捷组织转型提供咨询和培训服务。

这个问题也一直困扰着我 发表人 曹 云飞 发表于
Re: 这个问题也一直困扰着我 发表人 小刀 凉粉 发表于
Re: 这个问题也一直困扰着我 发表人 陈 之过 发表于
干吗不写成保护的方法? 发表人 jim han 发表于
Re: 干吗不写成保护的方法? 发表人 小刀 凉粉 发表于
的确是个很麻烦的问题,不过…… 发表人 Zhao Jeffrey 发表于
  1. 返回顶部

    这个问题也一直困扰着我

    发表人 曹 云飞

    我不能接受不应该有私有方法的说法,这与oo中封装的思想背道而驰。但是测试私有方法太麻烦,没有找到好的解决方法。

  2. 返回顶部

    Re: 这个问题也一直困扰着我

    发表人 小刀 凉粉

    我的做法就是把需要测试的私有方法,private标识符去掉

  3. 返回顶部

    干吗不写成保护的方法?

    发表人 jim han

    我觉得可以采用两种办法来解决
    1.把私有的改成保护的,这样测试用例测试的时候对测试类的子类进行测试,这个子类里面可以把保护方法暴露出来。不过这样做很累,但它没有破坏面向对象的封装。

    2.采用python的方法,用约定来区分私有还是公共,虽然所有方法都是公共的,但是根据约定还是可以分清楚哪些是私有的,哪些是公共的,这样测试起来也容易,而且面向对象的原则也没有破坏。

  4. 返回顶部

    Re: 干吗不写成保护的方法?

    发表人 小刀 凉粉

    convention over configuration..

  5. 返回顶部

    的确是个很麻烦的问题,不过……

    发表人 Zhao Jeffrey

    不过相对于私有方法,我在项目中的感觉是,一些internal类或internal方法更可能需要测试(internal是.net的概念,internal的成员只能在被所属的dll里的其他成员调用),所以理论上来说可以让测试的dll和被测试的dll成为friendly assembly,这样就可以访问internal成员了。
    但是这样也不好,首先太麻烦,又要强命名又要命令行的,其次这个方法太.net了,完全依赖平台特性……

  6. 返回顶部

    Re: 这个问题也一直困扰着我

    发表人 陈 之过

    在我编写测试时,如果觉得有强烈的冲动促使我去测试一个私有方法,我就会把它看作一种暗示。它告诉我,我的类已经被封装得趋近于封闭了,测试代码无法再通过公共接口来“理解”这个类的行为。我顺从了这个暗示的召唤,重新构建了代码。通常我都会把这个私有方法(可能还有一些相关的方法)挪到一个新的类里面,在那里它不再是私有,可以让测试代码访问。
    我认为这段话说的已经很明白了,可能是每个人的理解不同吧,我觉得他们说的都有道理,而且也不矛盾,哈哈,我都不知道我说什么呢

深度内容

大规模视频网站的计费与流量管理

本次分享将会就大规模视频网站的计费与流量管理这个话题,从操作层面细细进行讲解和分析,为系统工程师们揭示平日里我们没有关心的另一些内容。同时也希望本次分享能揭示行业中的一些“潜规则”,让互联网行业的流量与带宽管理更为开放与简洁。
本次演讲视频录制于QCon杭州2011

专访Jeffery Richter:Windows 8是微软的重中之重

Jeffery Richter以其多本Windows核心技术的经典著作而闻名,同时,他深入掌握微软的.NET等一系列核心技术,2012年1月,Jeffery Richter在北京接受了InfoQ中文站的专访,谈到Windows 8和WinRT编程,并就异步编程、Windows编程中的可扩展性、性能和安全性方面给出自己的建议。

应用云平台的可用性——从新浪SAE看云平台设计

云计算平台的可用性,相比传统互联网服务而言,更加复杂和困难,也更具有挑战性。本文借助新浪SAE云平台为读者讲述了云平台可用性的定义、如何打造高可用的平台,以及对云计算的用户提出了建议。

JVM定制改进 @ 淘宝

淘宝高度重视Java平台的健康发展,组建了一个团队专注于Java平台的底层部分的性能、功能与稳定性改进;工作主要基于OpenJDK中的HotSpot VM开展,其中一些通用的功能随后也会逐渐反馈给OpenJDK社区。希望能与使用Java平台开发应用的大家交流经验。
本次演讲视频录制于QCon杭州2011

"伤得起"的云计算应用——对云端应用之架构的思考

2011年4月21日至22日是值得云计算从业者纪念的日子。Amazon的IaaS服务出现故障,导致许多商业网站的服务中断,影响非常严重。作为云计算用户,我们需要思考的是,如何保证即便在云服务不可用的情况,我们的应用架构仍然能够屹立不倒?本文正是站在云计算用户的角度试图探讨这一问题。

让交付的速度跟上思考的速度

12人的技术团队,4组刀片服务器,每月20亿的访问量,每日1次准时部署,99.9%的可用性。这可能吗?当然。想知道如何做的吗?百姓网将与您分享他们在DevOps实践过程中的经验和技巧。
本次演讲视频录制于QCon杭州2011

架构之路——穿行在产品和业务之间

篱笆作为一家起源于社区的电子商务公司,反映到技术层面就是同时要面对产品和业务,以及经营战略的变化调整。如何在产品和业务的夹缝之间完成技术架构的抽象与平衡,寻找更有效的价值定位,这当中有些经验教训和个人感悟愿与众人分享。
本次演讲视频录制于QCon杭州2011

特性注入:成功三部曲

本文将对特性注入以及相关方法做一个扫盲性的介绍。我们会解释这个框架的关键要素,并附上实例来证实它们。为了让文章保持相对较短,我们不会深入到某个工具或方法中,而是会给出一些参考资料,以便大家做进一步的研究。