关于软件测试:单元测试

上博我写了测试的重要性。现在我来谈谈软件开发最基本的测试:单元测试,unit testing。

单元测试主要用来检测某class,function,method的正确性。我想绝大多数工程师在编程时都会做各种各样的单元测试。但直到约上世纪末和本世纪初,系统性、自动化的单元测试机制才被真正地建立起来注,见下。说到这里,我们必须提到Kent Beck和Erich Gamma。

Kent Beck在90年代末用Smalltalk编程,在那段时期他写出SUnit,是用Smalltalk写出的给Smalltalk程序做单元测试的架构。在此基础之上,他和Erich Gamma携手创建了JUnit。JUnit是用Java写成的用来做Java单元测试的架构。从JUnit开始,统称为xUnit的测试架构以燎原之势传入到其它语言:Python(unittest),PHP(PHPUnit),NUnit(.Net语言如C#,VB.net)等。

xUnit的架构和基本思路实际上很简单:Arrange-Act-Assert:
1.把输入值和期望值安排好,必要时可以装逼(mock)。mock是当你的单元测试需要大、笨重、或复杂的外部资源支持时(如数据库,其它复杂API等等),你可以用个假模子mock来代替。这一步是Arrange,设定期望值;
2.调动要被测试的function/method/class,得到实际值,这是Act;
3.比较期望值和实际值,报出测试结果,这是Assert.

或许你会说,这有啥大不了的,我编程时所做的随机测试就是这么做的吗。没错,但像xUnit这样的测试机制提供了自动化、可重复性和方便性等特点。

1.自动化
良好的xUnit测试机制有所谓的test harness,即各种脚手架、工具等配套的捆绑机制。在按xUnit规范写出测试案例后,可以很方便地用该捆绑机制轻松调用全部或部分测试案例,不用笨手笨脚地做手动调节;

2.即时性
和上文紧密相关的是xUnit带来的即时性。在写出一个测试案例后,你可以很方便得用copy/paste/adjust来写出更多其它测试案例。因为有自动化机制,运行这些案例会很方便快捷,成功与否,结果立现。这样你就可以在思路、信息还停留在脑海之时,趁热打铁,迅速、有效地解决这个问题。顺便说一句,英语中也有这一俚语:strike while the iron is hot。不知该成语是否是翻译、借用来(中英或英中),我感觉自发生成的可能性大些。

单元测试是你的安全网。随着你单元测试的增多,你的安全网就变得越来越密集,漏网之鱼就会越来越少。测试给你的软件质量提供了足够的保障。

如果说我们对单元测试的重要性和自动化有了共识,我有以下想法和你共勉,让我们一起来学习和提高。弄好测试,如俗谚所说,磨刀不费砍柴工,会大大提高你的功力!

1.搜索出并安装适合你编程语言的xUnit测试框架。比方说你写PHP,那你可以用PHPUnit。如你用Python,如果是2.7以后的话,你可以用标准的unittest模块来做测试:注意要安装nose来做这个测试的harness,来方便地调用你的测试案例。像其它语言,大多数都会有xUnit,搜搜就可以找到;

2.花时间学习如何写单元测试案例和如何有效地调用单元测试。相关的tutorial,how to等应当不少;

3.在做新开发时,要给新function/method/class写单元测试。当有时间或需要修改已存在代码时,如那段代码没单元测试,逐步引进单元测试;

4.单元测试也是代码的一部分,当然要进入代码管理库;

5.用copy和paste,写出各种满足边缘参数、一般参数等各种情况下的测试案例。硬盘便宜,多存几个案例占不了多大空,注意好的文档和命名方式对案例的管理很有帮助;

6.如果在整合测试/integration test或质量检测/quality assurance甚至是生产环境中发现你的function/method/class出现问题时,请首先写出个单元测试案例来捕捉这条漏网之鱼,然后修改代码来让测试通过。这样你的安全网就会被织得更紧一些。
在完成这个修改之后,你要反思一下为什么一开始你没想到要写这个测试?为什么没有想到鱼会有这种形状和技巧来挣脱你已经编织的网?通过这种反思,你会慢慢增加你的编程洞察力、嗅觉、和敏锐。

好,先写到这里。下一篇继续。我可能会写integration testing和continuous integration testing。或者专门写一下单元测试的应用实例如Python。如有问题或评论,欢迎提出,我们一起切磋,共同前进。

注:Perl的TAP(Test Anything Protocol)值得专门提一下。早在1987年,即随Perl第一版发布,就有了自己的单元测试机制。这比SUnit(xUnit之前身)要早10年左右。之后大部分在CPAN上公布的模块都经过了Test::More的符合TAP规格的单元测试。我个人以为这是Perl作为元老级脚本语言,至今仍威风八面、历久弥新的主要原因之一。所以如果你用Perl编程,我强烈建议你掌握Test::More和相关的Test::Harness模块。

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.