
2.1 使用功能测试驱动开发一个最简可用的应用
使用Selenium实现的测试可以驱动真正的网页浏览器,让我们能从用户的角度查看应用是如何运作的。因此,我们把这类测试叫作功能测试。
这意味着,功能测试在某种程度上可以作为应用的说明书。功能测试的作用是跟踪用户故事(User Story),模拟用户使用某个功能的过程,以及应用应该如何响应用户的操作。
术语:功能测试=验收测试=端到端测试
我所说的功能测试,有些人喜欢称之为验收测试(acceptance test)或端到端测试(endto-end test)。这类测试最重要的作用是从外部观察整个应用是如何运作的。另一个术语是黑箱测试(black box test),因为这种测试对所要测试的系统内部一无所知。
功能测试应该有一个人类可读、容易理解的故事。为了叙事清楚,可以把测试代码和代码注释结合起来使用。编写新功能测试时,可以先写注释,勾勒出用户故事的重点。这样写出的测试人类可读,甚至可以作为一种讨论应用需求和功能的方式分享给非程序员看。
TDD常与敏捷软件开发方法结合在一起使用,我们经常提到的一个概念是“最简可用的应用”,即我们能开发出来的最简单的而且可以使用的应用。下面我们就来开发一个最简可用的应用,尽早试水。
最简可用的待办事项清单其实只要能让用户输入一些待办事项,并且用户下次访问应用时这些事项还在即可。
打开functional_tests.py,编写一个类似下面的故事:
functional_tests.py
from selenium import webdriver browser = webdriver.Firefox() # 伊迪丝听说有一个很酷的在线待办事项应用 # 她去看了这个应用的首页 browser.get('http://localhost:8000') # 她注意到网页的标题和头部都包含“To-Do”这个词 assert 'To-Do' in browser.title # 应用邀请她输入一个待办事项 # 她在一个文本框中输入了“Buy peacock feathers”(购买孔雀羽毛) # 伊迪丝的爱好是使用假蝇做饵钓鱼 # 她按回车键后,页面更新了 # 待办事项表格中显示了“1: Buy peacock feathers” # 页面中又显示了一个文本框,可以输入其他的待办事项 # 她输入了“Use peacock feathers to make a fly”(使用孔雀羽毛做假蝇) # 伊迪丝做事很有条理 # 页面再次更新,她的清单中显示了这两个待办事项 # 伊迪丝想知道这个网站是否会记住她的清单 # 她看到网站为她生成了一个唯一的URL # 而且页面中有一些文字解说这个功能 # 她访问那个URL,发现她的待办事项列表还在 # 她很满意,去睡觉了 browser.quit()
我们有个词来形容注释
我开始在Resolver工作时,出于善意习惯在代码中加入密密麻麻的详细注释。我的同事告诉我:“哈利,我们有个词来形容注释,我们把注释叫作谎言。”我很诧异:可我在学校学到的是,注释是好的习惯啊?
他们说得夸张了。注释有其作用,可以添加上下文,说明代码的目的。他们的意思是,简单重复代码意图的注释毫无意义,例如:
# 把wibble的值增加 1 wibble += 1
这样的注释不仅毫无意义,还有一定危险,如果更新代码后没有修改注释,会误导别人。我们要努力做到让代码可读,使用有意义的变量名和函数名,保持代码结构清晰,这样就不再需要通过注释说明代码做了什么,只要偶尔写一些注释说明为什么这么做。
有些情况下注释很重要。后文会看到,Django在其生成的文件中用到了很多注释,这是解说API的一种方式。而且还在功能测试中使用注释描述用户故事——把测试提炼成一个连贯的故事,确保我们始终从用户的角度测试。
这个领域中还有很多有趣的知识,例如行为驱动开发(Behaviour Driven Development,详情参见附录E)和测试DSL(Domain Specific Language,领域特定语言)。这些知识已经超出本书的范畴了。
你可能已经发现了,除了在测试中加入注释之外,我还修改了assert这行代码,让其查找单词“To-Do”,而不是“Django”。这意味着现在我们期望测试失败。运行这个测试。
首先,启动服务器:
$ python manage.py runserver
然后在另一个shell中运行测试:
$ python functional_tests.py
Traceback (most recent call last):
File "functional_tests.py", line 10, in <module>
assert 'To-Do' in browser.title
AssertionError
这就是预期失败。其实失败是好消息,虽不像测试通过那么令人振奋,但至少事出有因,证明测试编写得正确。