预计阅读本页时间:-
6.5 测试序列与并行
在执行大量测试时,按它们被运行的情况进行分析是很有用的。类似nosetests这样的工具只是将结果输出到stdout,即标准输出,但这对测试结果的解析或分析并不方便。
subunit(https://pypi.python.org/pypi/python-subunit)是用来为测试结果提供流协议(streaming protocol)的一个Python模块。它支持很多有意思的功能,如聚合测试结果1或者对测试的运行进行记录或归档等。
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
使用subunit运行测试非常简单:
$ python -m subunit.run test_scenario
这条命令的输出是二进制数据,所以除非有能力直接阅读subunit协议,否则在这里直接再现它的输出结果实在是没什么意义。不过,subunit还支持一组将其二进制流转换为其他易读格式的工具,如示例6.12所示。
示例6.12 使用subunit2pyunit
$ python -m subunit.run test_scenario | subunit2pyunit
test_scenario.TestPythonErrorCode.test_python_status_code_handling(Not
found)
test_scenario.TestPythonErrorCode.test_python_status_code_handling(Not
found) ... ok
test_scenario.TestPythonErrorCode.test_python_status_code_handling(Client
error)
test_scenario.TestPythonErrorCode.test_python_status_code_handling(Client
error) ... ok
test_scenario.TestPythonErrorCode.test_python_status_code_handling(Server
error)
test_scenario.TestPythonErrorCode.test_python_status_code_handling(Server
error) ... ok
---------------------------------------------------------
Ran 3 tests in 0.061s
OK
这样的结果就容易理解了。你应该可以认出这个关于场景测试的测试集来自6.4节。其他值得一提的工具还有subunit2csv、subunit2gtk和subunit2junitxml。
subunit还可以通过传入discover参数支持自动发现哪个测试要运行。
$ python -m subunit.run discover | subunit2pyunit
test_scenario.TestPythonErrorCode.test_python_status_code_handling(Not
found)
test_scenario.TestPythonErrorCode.test_python_status_code_handling(Not
found) ... ok
test_scenario.TestPythonErrorCode.test_python_status_code_handling(Client
error)
test_scenario.TestPythonErrorCode.test_python_status_code_handling(Client
error) ... ok
test_scenario.TestPythonErrorCode.test_python_status_code_handling(Server
error)
test_scenario.TestPythonErrorCode.test_python_status_code_handling(Server
error) ... ok
---------------------------------------------------------
Ran 3 tests in 0.061s
OK
也可以通过传入参数--list只列出测试但不运行。要查看这一结果,可以使用subunit-ls。
$ python -m subunit.run discover --list | subunit-ls --exists
test_request.TestPython.test_bad_status_code
test_request.TestPython.test_ioerror
test_request.TestPython.test_python_is
test_request.TestPython.test_python_is_not
test_scenario.TestPythonErrorCode.test_python_status_code_handling
提示
可以使用--load-list选项指定要运行的测试的清单而不是运行所有的测试。
在大型应用程序中,测试用例的数量可能会多到难以应付,因此让程序处理测试结果序列是非常有用的。testrepository包(https://pypi.python.org/pypi/testrepository)目的就是解决这一问题,它提供了testr程序,可以用来处理要运行的测试数据库。
$testr init
$ touch .testr.conf
% python -m subunit.run test_scenario | testr load
Ran 4 tests in 0.001s
PASSED (id=0)
$ testr failing
PASSED (id=0)
$ testr last
Ran 3 tests in 0.001s
PASSED (id=0)
$ testr slowest
Test id Runtime (s)
---------------------------------------------- -----------
test_python_status_code_handling(Not found) 0.000
test_python_status_code_handling(Server error) 0.000
test_python_status_code_handling(Client error) 0.000
$ testr stats
runs=1
一旦subunit的测试流被运行并加载到testrepository,接下来就很容易使用testr命令来操作了。
显然,每次手工处理要运行的测试是很烦人的。因此,应该“教会”testr如何执行要运行的测试,以便它可以自己去加载测试结果。这可以通过编辑项目的根目录中的.testr.conf文件(见示例6.13)来实现。
示例6.13 .testr.conf文件
[DEFAULT]
test_command=python -m subunit.run discover . $LISTOPT $IDOPTION 1
test_id_option=--load-list $IDFILE 2
test_list_option=--list 3
1 执行testr run时要运行的命令。
2 加载测试列表要运行的命令。
3 列出测试要运行的命令。
第一行的test_command是最关键的。现在只需要运行testr run就可以将测试加载到testrepository中并执行。
注意
如果习惯用nosetests,testr run现在是等效的命令。
另外两个选项可以支持测试的并行运行。通过给testr run加上--prallel选项即可轻松实现,如示例6.14所示。并行运行测试可以极大地加速测试过程。
示例6.14 运行testr run --parallel
$ testr run --parallel
running=python -m subunit.run discover . --list
running=python -m subunit.run discover . --load-list /tmp/tmpiMq5Q1
running=python -m subunit.run discover . --load-list /tmp/tmp7hYEkP
running=python -m subunit.run discover . --load-list /tmp/tmpP_9zBc
running=python -m subunit.run discover . --load-list /tmp/tmpTejc5J
Ran 26 (+10) tests in 0.029s (-0.001s)
PASSED (id=7, skips=3)
在后台,testr运行测试列出操作,然后将测试列表分成几个子列表,并分别创建Python进程运行测试的每个子列表。默认情况下,子列表的数量与当前使用的机器的CPU数目相等。可以通过加入--concurrency标志设置进程的数目。
$ testr run --parallel --concurrency=2
可以想象,类似subunit和testrepository这样的工具将为测试效率的提升带来更多可能,而本节只是一个大概介绍。熟悉这些工具是非常值得的,因为测试会极大地影响你将要开发和发布的软件的质量。利用这些有力的工具能够节省很多时间。
testrepository也可以同setuptools集成,并且为其部署testr命令。这使得与基于setup.py工作流的集成更加容易,例如,可以围绕setup.py记录整个项目。setup.py testr命令可以接受一些选项,如--testr-args(通过它可以为testr加入更多选项)或者--coverage(这将在下一节介绍)。
1甚至可以支持来自不同源程序或语言的测试结果。