2.2 Python标准库中的unittest模块

上述测试中有几个恼人的问题需要处理。首先,“AssertionError”消息没什么用,如果测试能指出在浏览器的标题中到底找到了什么就好了。其次,Firefox窗口一直停留在桌面上,如果能自动将其关闭就好了。

要解决第一个问题,可以使用assert关键字的第二个参数,写成:

assert 'To-Do' in browser.title, "Browser title was " + browser.title

Firefox窗口可在try/finally语句中关闭。但这种问题在测试中很常见,标准库中的unittest模块已经提供了现成的解决方法。使用这种方法吧!在functional_tests.py中写入如下代码:

functional_tests.py

from selenium import webdriver
import unittest
class NewVisitorTest(unittest.TestCase):  ➊
    def setUp(self):  ➌
        self.browser = webdriver.Firefox()
    def tearDown(self):  ➌
        self.browser.quit()
    def test_can_start_a_list_and_retrieve_it_later(self):  ➋
        # 伊迪丝听说有一个很酷的在线待办事项应用
        # 她去看了这个应用的首页
        self.browser.get('http://localhost:8000')
        # 她注意到网页的标题和头部都包含“To-Do”这个词
        self.assertIn('To-Do', self.browser.title)  ➍
        self.fail('Finish the test!')  ➎
        # 应用邀请她输入一个待办事项
        [其余的注释和之前一样]
if __name__ == '__main__':  ❻
    unittest.main(warnings='ignore')  ❼

你可能注意到以下几个地方了。

❶ 测试组织成类的形式,继承自unittest.TestCase。

❷ 测试的主要代码写在名为test_can_start_a_list_and_retrieve_it_later的方法中。名字以test_开头的方法都是测试方法,由测试运行程序运行。类中可以定义多个测试方法。为测试方法起个有意义的名字是个好主意。

❸ setUp和tearDown是特殊的方法,分别在各个测试方法之前和之后运行。我使用这两个方法打开和关闭浏览器。注意,这两个方法有点类似try/except语句,就算测试中出错了,也会运行tearDown方法。唯有一个特例:如果setUp方法抛出异常,tearDown方法就不会运行。测试结束后,Firefox窗口不会一直停留在桌面上了。

❹ 使用self.assertIn代替assert编写测试断言。unittest提供了很多这种用于编写测试断言的辅助函数,如assertEqual、assertTrue和assertFalse等。更多断言辅助函数参见unittest的文档。

❺ 不管怎样,self.fail都会失败,生成指定的错误消息。我使用这个方法提醒测试结束了。

❻ 最后是if __name__ == '__main__'分句(如果你之前没见过这种用法,我告诉你,Python脚本使用这个语句检查自己是否在命令行中运行,而不是在其他脚本中导入)。我们调用unittest.main()启动unittest的测试运行程序,这个程序会在文件中自动查找测试类和方法,然后运行。

❼ warnings='ignore'的作用是禁止抛出ResourceWarning异常。写作本书时这个异常会抛出,但你阅读时我可能已经把这个参数去掉了。你可以把这个参数删掉,看一下效果。

如果你阅读Django关于测试的文档,可能会看到有个名为LiveServerTestCase的类,而且想知道我们现在能否使用它。你能阅读这份友好的手册真是值得表扬!目前来说,LiveServerTestCase有点复杂,但我保证后面的章节会用到。

来试一下这个测试。

$ python functional_tests.py
F
======================================================================
FAIL: test_can_start_a_list_and_retrieve_it_later (__main__.NewVisitorTest)
 ---------------------------------------------------------------------
Traceback (most recent call last):
  File "functional_tests.py", line 18, in
test_can_start_a_list_and_retrieve_it_later
    self.assertIn('To-Do', self.browser.title)
AssertionError: 'To-Do' not found in 'Welcome to Django'

 ---------------------------------------------------------------------
Ran 1 test in 1.747s

FAILED (failures=1)

这样是不是更好了?这个测试清理了Firefox窗口,显示了一个排版精美的报告,指出运行了几个测试,其中有几个测试失败了,而且assertIn还显示了一个有利于调试的错误消息。太棒了!