Python 高手编程系列八十四:测试环境与依赖兼容性
环境隔离的重要性在本书中已经提到很多次了。通过在应用程序级虚拟环境和系统级系统虚拟化上隔离执行环境你可以确保测试可以在可重复的条件下运行。这样你可以避免受因破坏依赖关系导致的罕见且模糊的问题。正确隔离测试环境的最佳方法是使用支持系统虚拟化的持续集成系统。对于开源项目有很好的免费解决方案如 Travis CILinux 和 OS X或 AppVeyorWindows但是如果你需要这样的东西来测试私有的软件很可能你需要花一些时间在一些现有的开源 CI工具GitLab CI、Jenkins 和 Buildbot之上自己构建这样的解决方案。依赖矩阵测试大多数情况下开源 Python 项目的测试矩阵主要关注不同的 Python 版本很少关注不同的操作系统。对于纯 Python 并且没有与操作系统互相操作问题的项目没有必要在不同的系统上进行测试和构建。但是有一些项目特别是作为编译的 Python 扩展分发时应该在各种目标操作系统上进行测试。对于开源项目甚至不得不使用几个独立的 CI 系统进行构建用来适配 3 种最流行的操作系统Windows、Linux 和 Mac OS X。如果你正在寻找一个很好的例子你可以看一下这个小 pyrilla 项目参考 https://github.com/swistakm/pyrilla这是一个简单的 C 音频 Python 扩展。它同时使用 Travis CI 和 AppVeyor目的是为了提供 Windows 和 Mac OS X 的编译版本以及大范围的 CPython 版本。但是测试矩阵的维度不会局限在系统和 Python 版本上。提供与其他软件如缓存、数据库或系统服务集成的软件包通常应在各种版本的集成应用程序上进行测试。tox参考http://tox.readthedocs.org是一个好工具可以使这样的测试更加容易。它提供了一种简单的方法来配置多个测试环境并使用一个 tox 命令运行所有测试。它是一个非常强大和灵活的工具并且也很容易使用。展示它的用法的最好的方式是给你一个配置文件的例子其实它就是 tox 的核心。这里有一个 tox.ini 文件它来自 django-userena 项目参考 https://github.com/bread-andpepper/django-userena[tox]downloadcache {toxworkdir}/cache/envlist ; py26 support was dropped in django1.7py26-django{15,16},; py27 still has the widest django supportpy27-django{15,16,17,18,19},; py32, py33 support was officially introduced in django1.5; py32, py33 support was dropped in django1.9py32-django{15,16,17,18},py33-django{15,16,17,18},; py34 support was officially introduced in django1.7py34-django{17,18,19}; py35 support was officially introduced in django1.8py35-django{18,19}[testenv]usedevelop Truedeps django{15,16}: southdjango{15,16}: django-guardian1.4.0django15: django1.5.12django16: django1.6.11django17: django1.7.11django18: django1.8.7django19: django1.9coverage: django1.9coverage: coverage4.0.3coverage: coveralls1.1basepython py35: python3.5py34: python3.4py33: python3.3py32: python3.2py27: python2.7py26: python2.6commands{envpython} userena/runtests/runtests.py userenaumessages{posargs}[testenv:coverage]basepython python2.7passenv TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCHcommandscoverage run --sourceuserena userena/runtests/runtests.pyuserenaumessages {posargs}coveralls这个配置允许你在 5 个不同版本的 Django 和 6 个版本的 Python 上测试 django-userena项目。并不是每个 Django 版本都可以在每个 Python 版本上工作tox.ini 文件使得定义这样的依赖性约束相对容易。在实践中整个构建矩阵包括 21 个唯一的环境包括用于代码覆盖收集的特殊环境。手动创建每个测试环境需要付出很多努力即使使用 shell 脚本也不太容易。Tox 是很棒但如果我们想改变测试环境中其他一些不是纯 Python 依赖的元素它的使用会变得很复杂。有这样一种情况当我们需要在不同版本的系统包和支持服务上测试时。解决这个问题的最好方法是再次使用良好的持续集成系统这可以使你能够轻松地定义环境变量的矩阵并在虚拟机上安装系统软件。使用 Travis CI 的一个很好的例子是 ianitor项目参考 https://github.com/ClearcodeHQ/ianitor/在第 9 章文档化你的项目中已经提到过它。这是一个简单的实用程序用于 Consul 服务发现。Consul 项目拥有一个非常活跃的社区每年都会发布很多版本。对该服务的各种版本进行测试是很有必要的。这确保ianitor 项目仍然是该软件的最新版本并且也不会破坏与以前的 Consul 版本的兼容性。以下是 Travis CI 的.travis.yml 配置文件的内容它允许你针对 3 个不同的 Consul 版本和4 个 Python 解释器版本进行测试如下所示language: pythoninstall: pip install tox --use-mirrorsenv:matrix:consul 0.4.1TOX_ENVpy27 CONSUL_VERSION0.4.1TOX_ENVpy33 CONSUL_VERSION0.4.1TOX_ENVpy34 CONSUL_VERSION0.4.1TOX_ENVpy35 CONSUL_VERSION0.4.1consul 0.5.2TOX_ENVpy27 CONSUL_VERSION0.5.2TOX_ENVpy33 CONSUL_VERSION0.5.2TOX_ENVpy34 CONSUL_VERSION0.5.2TOX_ENVpy35 CONSUL_VERSION0.5.2consul 0.6.4TOX_ENVpy27 CONSUL_VERSION0.6.4TOX_ENVpy33 CONSUL_VERSION0.6.4TOX_ENVpy34 CONSUL_VERSION0.6.4TOX_ENVpy35 CONSUL_VERSION0.6.4coverage and style checksTOX_ENVpep8 CONSUL_VERSION0.4.1TOX_ENVcoverage CONSUL_VERSION0.4.1before_script:wget https://releases.hashicorp.com/consul/KaTeX parse error: Expected group after _ at position 25: …ERSION}/ consul_̲{CONSUL_VERSION}_linux_amd64.zipunzip consul_${CONSUL_VERSION}_linux_amd64.zipstart-stop-daemon --start --background --execpwd/consul –agent -server -data-dir /tmp/consul -bootstrap-expect1script:tox -e $TOX_ENV前面的示例为 ianitor 代码提供了 14 个唯一的测试环境包括 pep8 和 coverage 构建。此配置还使用 tox 在 Travis VM 上创建实际测试虚拟环境。实际上这是一个非常流行的方法用于 tox 与不同的 CI 系统的整合。通过将更多的测试环境配置迁移到 tox 中你可以降低将自己锁定到单个供应商的风险。诸如安装新服务或定义系统环境变量的事情大多数 Travis CI 竞争对手都支持因此如果市场上有更好的产品或者 Travis 改变对开源项目的定价模型你可以很容易地切换到其他的服务提供商。