![测试驱动开发:入门、实战与进阶](https://wfqqreader-1252317822.image.myqcloud.com/cover/702/48593702/b_48593702.jpg)
1.3 第一个失败的测试
我们先来做清单里的第一个功能:
![](https://epubservercos.yuewen.com/2F0B0F/28235549002740206/epubprivate/OEBPS/Images/44_04.jpg?sign=1738860781-YA9Gl9UCcj4MItDTHW86olLB5w6kPt1p-0-95a820b787b7a1d1d4797e7b20c2800e)
首先,编写一个失败的测试,这就是RGR环中的第一个环节:红。
1.3.1 Go
在go文件夹里新建一个名叫money_test.go的文件,然后我们就来编写第一个测试:
![](https://epubservercos.yuewen.com/2F0B0F/28235549002740206/epubprivate/OEBPS/Images/44_05.jpg?sign=1738860781-OqSTCCYUDwoYJ8kyuWgef8ktY7TDSlxk-0-f1f65eab0284c7f28f70930fea78b33d)
![](https://epubservercos.yuewen.com/2F0B0F/28235549002740206/epubprivate/OEBPS/Images/44_06.jpg?sign=1738860781-E4M6UQocsC8rudnmeJLlnBxhp0WJF107-0-7f03dd5b734570460bf41ebd74ab60d8)
![](https://epubservercos.yuewen.com/2F0B0F/28235549002740206/epubprivate/OEBPS/Images/45_01.jpg?sign=1738860781-Gfy7wNTaRDSWQkAB0T8HLjIltOdRRSke-0-e56b01ad22af269b4b838aa765d135b3)
❶包声明。
❷引入testing包,后面的t.Errorf需要用到这个包。
❸这是我们的测试方法,该方法必须以Test开头,并拥有一个*testing.T型的参数。
❹这是个用来表示“USD 5”(5美元)的结构体,目前还不存在Dollar结构体。
❺调用有待接受测试的方法,也就是Times方法,该方法目前并不存在。
❻将实际值与我们所期望的值相对比。
❼确保该测试会在期望值与实际值不符时失败。
这个测试函数包含许多为了做测试而必须要写的样板代码。
package main这样一条声明用来表示其后的所有代码都是main包的一部分。如果想编写可单独执行的Go程序,那么必须这样做。包管理(https://oreil.ly/yvh3S)是Go语言中一个较为复杂的功能。我们会在第5章详细讨论。
接下来,我们用import语句引入testing包。后面的单元测试需要使用该包。
单元测试函数(即TestMultiplication函数)是这段代码的主要内容。我们在该函数中声明了一个实体,用来表示“USD 5”。我们还创建了一个名叫fiver的变量,并把这个amount字段为5的结构体设为该变量的初始值(或者说,我们用这个amount字段为5的结构体来初始化该变量)。然后,我们将fiver与2相乘〔并用变量tenner来表示结果〕。我们希望相乘的结果是10美元,也就是说,tenner变量的amount字段必定等于10。如果不是这样,就打印一条格式整齐的错误消息,以显示实际的值(无论这个值是多少,我们都把它写在这条消息之中)。
我们在TDD Project Root文件夹中用go test-v .命令运行测试,大家应该会看到下面这样的错误:
![](https://epubservercos.yuewen.com/2F0B0F/28235549002740206/epubprivate/OEBPS/Images/45_02.jpg?sign=1738860781-tBR45Q2zpf7VBPbwgwFBT6BpRu68a6pq-0-442d6469d445bb89fce2573744311ab6)
这条信息说得很明白:我们写的测试失败(FAIL)了。到这里,我们就完成了TDD的第一步,也就是写一个失败的测试。
go test-v.命令用来运行当前文件夹中的测试,go test-v ./...命令[1]用来运行当前文件夹与各个子文件夹中的测试。-v选项(或者说开关)的意思是,打印详尽的输出信息。
1.3.2 JavaScript
在js文件夹中新建名叫test_money.js的文件,然后开始编写我们的第一个测试用例:
![](https://epubservercos.yuewen.com/2F0B0F/28235549002740206/epubprivate/OEBPS/Images/46_02.jpg?sign=1738860781-I2XcyCn8j2XGwGQWezG9IVudnhAbtFb6-0-8c9487cea91b920451acc3a98693ad45)
![](https://epubservercos.yuewen.com/2F0B0F/28235549002740206/epubprivate/OEBPS/Images/46_03.jpg?sign=1738860781-HTp6hTirg5pRblnWDvlLsaESNtUmC8k9-0-0c8cf897ee776d5313daf36205b6da40)
❶引入assert包,稍后的断言语句需要用到这个包。
❷创建一个表示“USD 5”的对象。目前还不存在这种Dollar对象。
❸调用有待接受测试的方法,也就是times方法。该方法目前并不存在。
❹通过strictEqual断言语句来对比实际值与我们所期望的值。
用JavaScript语言做测试时,几乎没有那种为了做测试而必须编写的样板代码,我们只需要用一行require语句把名为assert的NPM包引入就行了。
这行代码之后的三行代码是用来做测试的。我们创建一个表示5美元的对象,将其乘以2,并期望相乘的结果是10。
ES2015新增了用来声明变量的let关键字(https://oreil.ly/jBMPk)与用来声明常量的const关键字(https://oreil.ly/GfYQ5)。
我们在TDD Project Root目录下用node js/test_money.js运行测试,会看到像如下这样开头的一段错误信息:
![](https://epubservercos.yuewen.com/2F0B0F/28235549002740206/epubprivate/OEBPS/Images/46_05.jpg?sign=1738860781-pus7lOEdHk6wyYbclYyyMPnWALldCQ5I-0-da152940cd262d3a016bc79264a3cff3)
太棒了!我们已经写好了第一个失败的测试用例。
node file.js这样的命令用来运行名为file.js的JavaScript代码文件并输出运行结果。我们在本书中也采用这种格式的命令来运行测试。
1.3.3 Python
在py文件夹中新建名为test_money.py的文件,并开始编写我们的首个测试:
![](https://epubservercos.yuewen.com/2F0B0F/28235549002740206/epubprivate/OEBPS/Images/47_02.jpg?sign=1738860781-TI2UvvnESi3JGl9NkespShTNdgCQXWKI-0-3a50e16ead69ff886fba1d449cac5853)
![](https://epubservercos.yuewen.com/2F0B0F/28235549002740206/epubprivate/OEBPS/Images/47_03.jpg?sign=1738860781-X0RJbanbYLYs1S52F3J4n9VYljMKZ195-0-d87fb79661c14ec663b60c0238254587)
❶引入unittest包,后面要写的TestMoney类需要以该包中的TestCase类为超类。
❷这是我们自己的测试类,该类必须是unittest.TestCase类的子类。
❸测试方法的名称必须以test开头。
❹这是个用来表示“USD 5”(5美元)的对象。当前还不存在这种Dollar对象。
❺调用有待接受测试的times方法,该方法目前并不存在。
❻用assertEqual语句对比期望值与实际值。
❼按惯例编写__main__结构,以确保这个TestMoney类〔所在的test_money.py文件〕能够单独作为一个脚本运行。
为了用Python语言做测试,我们必须通过import关键字引入unittest包,并创建一个TestCase类的子类,还需要定义一个名称以test开头的函数。另外,为了让我们的测试类〔所在的test_money.py文件〕可以作为单独的程序运行,需要按照Python的惯例书写__main__结构(参见https://docs.python.org/3/library/__main__.html),以便在单独运行〔而不是作为其他脚本的一部分来运行〕test_money.py时,能够触发unittest.main()函数〔以启动测试〕。
这个测试函数(即testMultiplication函数)描绘我们期望代码如何运作。我们定义名为fiver的变量,并将其初始化为一个我们想要的对象,该对象应是Dollar类的实例(当然,目前这个类还不存在)。我们构造该对象时,向构造器传入5作为参数。然后,我们把fiver与2相乘,并将结果保存在tenner变量中。最后,我们期望tenner的amount应该是10。
我们在TDD_PROJECT_ROOT文件夹中,用python3 py/test_money.py-v命令运行这段代码时,会看到含有下列信息的错误:
![](https://epubservercos.yuewen.com/2F0B0F/28235549002740206/epubprivate/OEBPS/Images/48_01.jpg?sign=1738860781-Mg6PVn1gzQToBl92f4ufwK838B4JVplF-0-7ab07eb05f5670be8ca8fba387e83314)
好,我们已经把第一个失败的测试给写出来了!
python3 file.py-v格式的命令用来运行名为file.py的Python代码。-v的意思是显示详尽的输出信息。我们会采用这种格式的命令来运行本书的测试。