我们以前在编程的过程中,可能出现过这样的情形:我们编写了程序后运行,在命令行中输入数据,程序打印出结果,然后我们比较输出结果与我们预想的是否一样,如果不一样就修改程序直到结果相同为止,然后换一组输入数据,如果输出与预想不同就再次修改程序直到结果相同,如此反复。
我们可能还这样做过:为了简化上述步骤,我们建立一个批处理文件,其中包含如
a.exe<in.txt>out.txt
之类的语句,然后在in.txt中把输入数据按照预想的顺序输入,然后运行批处理文件,之后比较out.txt文件里的输出是否符合。可能做过ACM题库的同学有着更多类似这样的经历。
我的同学fafey(fafey的泡泡堂:" src="http://delacroix:8668/theme/images/Icon-Extlink.png" border=0http://blog.csdn.net/fafey/)曾经作了一个小程序,可以在左边的输入框中输入数据,然后选择可执行文件,运行,程序自动生成in.txt文件和批处理文件并运行,然后把out.txt中的内容输出到右边的输入框中。
我觉得的,以上这些,就是我们在不知道自动测试和没有自动测试工具下所作的自动测试的初级尝试。TDD更进一步,它不是编码后用测试检验,而是先写测试来推动编码。一个测试几乎就是一项需求的代码体现。
如今,自动测试工具xUnit系列给我们提供自动测试的可能。目前我比较常用的就是JUnit。因为很多Java IDE都集成了JUnit,提供了一系列方便自动测试的功能,如Eclipse,IntelliJ Idea,JBuilder等。C语言的cUnit和C++语言的cppUnit目前似乎还不成熟,但是已经有了RC版(可以在 sourceforge.net上找到)。.Net我不熟悉,好像已经有了这方面的工具。
在看完了《测试驱动开发》后,我尝试着使用测试驱动开发做了一个程序(还没有完成),是《Java 程序设计教程》(Java How To Program)里的一个贯穿全书的专题练习:建立Simpletron模拟器,并编写Simple语言的编译器和解释器。Simpletron是作者为这个练习设计的(后面的SML和Simple也是)一个虚拟机器,它使用SML(Simpletron Machine Language)机器语言,Simple语言是一种类Basic语言。因为这并不是编译原理的教材,所以作者把它设计成容易实现的形式,还提供了很多基础知识和预备练习,对计算机组成原理也起到了复习的作用,还涉及到了编译原理的部分知识,个人认为是一个很好的练习素材,值得推荐。
因为我毕竟也是第一次使用测试驱动开发,而且对TDD理解的也不是很深刻,自我感觉就是时而很爽,时而很不爽。
测试驱动开发大致可分成三个步骤:编写测试,使测试通过和重构。对于第二个步骤,因为TDD要求要以最快速度使测试通过,并为达此目的可以“不择手段”,因此,完成这一步骤可以说是轻而易举的,所以,TDD的难点也就在于测试的编写和重构这两部分。
我在实践过程中,发现即使遵照Kent的那些编写技巧,测试的编写也还是很难的。由于它要求编写者在测试中尽可能设计出“完美”的接口,所以对编写者的编程经验有一定的要求,编写者要对程序有一种经验性的直觉,这完全依赖于编写者的编程阅历及天赋,还有对所要解决的问题的认知程度。比如在我做的这个程序中,最后的程序应该是这个样子,运行后会在控制台中与用户形成交互式的操作,而我在刚开始设计出的接口却是方法调用形式的,没有交互行为,为了纠正错误,我修改了4个TestCase共11个测试,好在每个测试都不太大。在此之后,像这样的大规模改动还有几次,有的是因为后续的练习题目中改变了输入要求而不得不更改测试数据。
重构这里很难做。Kent的很多重构操作我还是觉得匪夷所思,不清楚他是如何想到的,所以也没办法很好的重构代码。我所能够做到的,就是寻找重复设计和重复代码,尽可能的消除重复,但是在优化结构上我实在是想不通,目前我只做了 Simpletron模拟器及SML,就是一个单个的类,我实在是想不出把它分成几个类的理由,因为测试没有这样的要求,测试一直都只对一个 simpletron对象操作,不知道是不是自己功力不够的原因。另外,因为SML使用四位十进制数(后来又要求四位十六进制数)作指令,我用了一个冗长的switch语句,总觉得这样不太好,也不知道如何改。我觉得自己对自己编写的代码没有信心,而且代码也确实质量不高,所以我觉得我应该阅读一些源代码,开源软件的源代码应该是一个很好的选择,而JUnit中的比较难的也就是反射,应该是一个比较简单的起点。
虽然做不到“code clean”,但是却可以做到“that works”。反正即使不采用TDD,我的代码也不是clean的,而且更加dirty。而TDD每一步都能得到可以正确执行的代码,又为code clean提供了策略。每次对代码改动,都可以运行测试来检验,虽然不能证明我的改动是正确的,但是至少不是错误的。
我觉得,但就个人开发而言,TDD是个很优秀的方法。我还要继续学习和实践,希望可以提高自己的编程效率。