来源: WingFire On Toplanguange
1.单元测试库要尽量少地增加开发人员的负担。额外负担必须尽可能直白,傻瓜化。
市面上的许多讲到单元测试的书都是以XUnit为蓝本的,这导致CppUnit的接受程度颇高。CppUnit中规中矩,四平八稳,但不够犀利。个人认为boost.test最简单,只要一个BOOST_AUTO_TEST_CASE就可以开始了。CppUnit则要复杂一点,而这种复杂性是多余的,甚至是有害的。用CppUnit的时候,我看到有人为了共享测试代码,随便在test case里面加函数,然后复用,结果导致case不独立。boost.test倾向于不要建立.h文件,所以要复用不方便(或者,不习惯在Cpp中复用),反而不容易犯错误。
2.实施单元测试,必须能够让程序员看得到好处并尽快受益。新项目必须尽早引入单元测试,要早在正式编码之前。
想立刻让UT变得完美是不可能的,行政命令也不会有好结果。在推行单元测试的时候,教育很重要。必须让同事能理解单元测试为什么有效,如何工作,UT编写准则之类的问题。另外,在工作多年的程序员(对UT缺乏认识的)中推行单元测试,阻力更大。更要注意教育和反馈。最好的反馈就是帮助他们从单元测试中获益。例如,修改更轻松,思维更面向接口,bug更少,代码更容易理解等等。作为推动者,有义务去主动发现这些改善之处并积极地反馈给程序员。从而增强应用UT的信心和意愿。
3.必须充分自动化。
UT的任务之一是给代码编织一层细密的保护网。程序员应该认识到,单元测试是为自己服务的,所以,我们要的是完成任务而不是展示。能够自动地完成任务则是最好的。如果单元测试过多地干扰程序员的正常思考,就会招致更多的抵触(抵触总是存在的)或敷衍。敷衍是可怕的。我向来是把单元测试的运行作为build的一个步骤的。成功的单元测试不需要输出任何信息,最多在全部passs的时候给个OK就足够了。图形界面的测试工具在我看来也是鸡肋,新手的玩具而已。图形界面既不利于参数化运行,也不方便自动化,实在是降低开发效率的杀手。
4.不要追求完美的UT。
不是所有东西都很容易测试。UT要求被测试的东西可重现,可观测。 基本上,大部分的物理操作因为缺乏可重复性或可观察性,很难测试,例如database,GUI (注意,这不意味着在实现一个GUI库或db driver时就不能做UT了)。勉强UT全覆盖,既不现实,也不实惠。并且,这很可能让UT变得复杂,高成本,这是非常危险的和不值得的。我的主张是,很难测,那就不测,但要正确应对。我的做法是将难测的部分隔离到一些抽象层当中去。然后为这些抽象层写MockObject即可测试了。我曾经应用在数据库应用中,并很自然的得到一个良好的数据访问的抽象层,单元测试就只测了这个抽象层。而实际的数据库访问中的物理操作部分,则从单元测试中剥离出去。如果坚持分离物理操作和逻辑操作的话,这个剥离出去的部分一般很小很有限,也很容易测试。相反,如果不剥离,将导致单元测试的结果要依赖数据库的状态。这种额外的依赖性没什么好处。这里的关键是,必须让不可测的部分尽可能隔离,尽可能小,尽可能地将逻辑操作从物理操作中分离出来。被隔离部分所包含的逻辑操作仍然需要写UT。