使用testrepository管理测试的运行
上面我们看到tox.ini文件中的commands参数中执行的是_tools/pretty_tox.sh_命令。这个脚本的内容如下:
#!/usr/bin/env bash set -o pipefail TESTRARGS=$1 # testr和setuptools已经集成,所以可以通过setup.py testr命令来执行 # --testr-args表示传递给testr命令的参数,告诉testr要传递给subunit的参数 # subunit-trace是os-testr包中的命令(os-testr是OpenStack的一个项目),用来解析subunit的输出的。 python setup.py testr --testr-args="--subunit $TESTRARGS" | subunit-trace -f retval=$? # NOTE(mtreinish) The pipe above would eat the slowest display from pbr's testr # wrapper so just manually print the slowest tests. echo -e "nSlowest Tests:n" # 测试结束后,让testr显示出执行时间最长的那些测试用例 testr slowest exit $retval |
too就是从tools/pretty_tox.sh这个命令开始调用testr来执行单元测试的。testr本身的配置是放在项目根目录下的.testr.conf文件:
[DEFAULT] test_command= ${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./keystone/tests/unit} $LISTOPT $IDOPTION test_id_option=--load-list $IDFILE test_list_option=--list group_regex=.*(test_cert_setup) # NOTE(morganfainberg): If single-worker mode is wanted (e.g. for live tests) # the environment variable ``TEST_RUN_CONCURRENCY`` should be set to ``1``. If # a non-default (1 worker per available core) concurrency is desired, set # environment variable ``TEST_RUN_CONCURRENCY`` to the desired number of # workers. test_run_concurrency=echo ${TEST_RUN_CONCURRENCY:-0} |
这个文件中的配置项可以从testr官方文档中找到。其中test_command命令表示要执行什么命令来运行测试用例,这里使用的是subunit.run,这个我们在上面提到过了。
到目前为止的流程就是:
tox建好virtualenv
tox调用testr
testr调用subunit来执行测试用例
每个OpenStack项目基本上也都是这样。如果你自己在开发一个Python项目,你也可以参考这个架构。
单元测试用例的代码架构
下面我们来看一下Keystone的单元测试代码是如何写的,主要是看一下其层次结构。每个OpenStack项目的单元测试代码结构可能都不一样,不过你了解完Keystone的结构之后,看其他项目的就会比较快了。
我们以一个测试类为例来分析测试代码的结构:keystone.tests.unit.test_v3_assignment:AssignmentTestCase。下面是这个类的继承结构,同一级别的缩进表示多重继承,增加缩进表示父类,这里删掉了不必要的路径前缀(从unit目录开始,如下所示:
# 这个测试类是测RoleAssignment的API的 unit.test_v3_assignment.RoleAssignmentBaseTestCase -> unit.test_v3.AssignmentTestMixin 这个类包含了一下测试Assignment的工具函数 -> unit.test_v3.RestfulTestCase 这个类是进行V3 REST API测试的基类,实现了V3 API的请求发起和校验 -> unit.core.SQLDriverOverride 用于修改各个配置的driver字段为sql -> unit.test_v3.AuthTestMixin 包含创建认证请求的辅助函数 -> unit.rest.RestfulTestCase 这个类是进行RESP API测试的基类,V2和V3的API测试 都是以这个类为基类,这个类的setUp方法会初始化数据库,创建好TestApp。 -> unit.TestCase 这个类是Keystone中所有单元测试类的基类,它主要初始化配置,以及初始化log -> unit.BaseTestCase 这个类主要是配置测试运行的基本环境,修改一些环境变量,比如HOME等。 -> oslotest.BaseTestCase 这个是在oslotest中定义的基类,原来所有的OpenStack项目的单元测试都继承自这个基类。 不过,这个继承在Keystone中已经被删除了,Keystone自己在unit.BaseTestCase中做了差不多的事情。 这个是2016-02-17做的变更,具体的可以查看这个revision 262d0b66c3bcb82eadb663910ee21ded63e77a78。 -> testtools.TestCase 使用testtools作为测试框架 -> unittest.TestCase testtools本身是unittest的扩展 |
从上面的层次结构可以看出,OpenStack中的大项目,由于单元测试用例很多(Keystone现在有超过6200个单元测试用例),所以其单元测试架构也会比较复杂。要写好单元测试,需要先了解一下整个测试代码的架构。
总结
本文我们了解了Python中的单元测试的概念和工具,并且通过Keystone项目了解了实际项目中的单元测试的架构,希望有助于各位读者更好的掌握OpenStack项目的单元测试基础。webdemo项目目前没有单元测试的代码,有兴趣的读者可以自己fork然后参考Keystone的架构为其增加完整的单元测试架构。
系列后记
这个系列我打算就此结束,到目前为止一共写了8篇文章,写写停停,前后写了9个月。这里也做个小结。
一开始写这个系列的文章是因为我自己在学习OpenStack开发的过程中遇到很多困难,很难找到所需的入门文章。所以打算写点文章,既能作为自己的总结,也能为其他人提供些帮助。如果这些文章能帮到你,我就非常的开心。当然,这些文章的质量肯定有好有坏,欢迎大家提意见,如果有时间,我会继续修改。
然后,我想说一下写这类文章的难点,主要是要保证细节都是正确的,然后又不能太啰嗦。
细节都是正确的。举个例子,大学的很多数据结构教材中的代码,你直接贴到电脑上,然后编译,大部分是编译不通过的。这个会让初学者非常沮丧。所以我希望能够保证这些文章里的细节都是正确的,包括一些工具的配置,如果觉得有必要,我也会描述下配置的作用,以及要去哪里找更多的信息。如果这方面有遗漏,请和我说。
不能太啰嗦。这8篇文章里涉及的库有好几十个,每个库如果都讲仔细了,那就会让文章显得非常啰嗦。但是又不能直接让读者去看库的官方文档,所以权衡内容也是很麻烦的。如果各位有这方面的建议,也请和我说。
这个系列的文章是关于OpenStack的基础知识,其实OpenStack开发还要涉及到很多其他的知识,比如消息队列、非阻塞IO等,而且还要了解整个OpenStack的开发生态,包括Gerrit评审系统、Zuul持续集成、devstack开发环境、oslo项目等。