许多开发人员使用 tox 作为 Python 中标准化和自动化测试的解决方案。然而,仅将该工具用于测试自动化严重限制了其功能和您可以实现的全部范围。例如, tox 也是“它在我的机器上工作”问题的一个很好的解决方案。这有几个原因,例如:
- 可以针对不同的 Python 依赖项版本运行测试
- 可以隔离环境变量
- 可以捕获并运行设置命令
此外,最重要的是,上面列出的操作可以在 Windows 、 macOS 和 Linux OS 上执行。在本教程中,我将深入探讨 tox 的工作原理以及如何使用它来节省宝贵的资源。我还将提供具体的代码示例来演示如何利用 tox 。
什么是 Tox?
如果你读了 tox documentation ,并从字面上理解它的意思,你可能会认为 tox 只是一个用来创建虚拟环境的工具,用来安装测试 Python 包所需的必要依赖项。
该文档指出,“ tox 旨在自动化和标准化 Python 中的测试。它是简化 Python 软件的打包、测试和发布过程的更大愿景的一部分。”该文档后来指出,“ tox 是一个通用的virtualenv管理和测试命令行工具。”。同一文档中的几个示例演示了 tox 用于构建文档和运行开发环境。
然而,最好将 tox 视为自动化某些工作流和管理虚拟环境的工具。 tox 文档中提供的示例配置文件如下所示。
# content of: tox.ini , put in same dir as setup.py
[tox]
envlist = py27,py36
[testenv]
# install pytest in the virtualenv where commands will be executed
deps = pytest
commands =
# NOTE: you can run any command line tool here - not just tests
pytest
请注意,该文件仅安装并运行 Pytest ;然而,文档指出,“您可以在这里运行任何命令行工具,而不仅仅是测试。”
tox 是如何工作的?
tox 文档的 System Overview 部分提供了一个工作流图(图 1 )。该图显示了 tox 如何通过将工作流分解为一系列步骤来工作,概述如下。
- 使用
tox.ini文件中定义的 Python 版本生成虚拟环境。 - 将
tox.ini文件的deps设置下列出的依赖项安装到虚拟环境中。如果创建了一个项目(可选),它还将安装该项目的sdist。 - 在隔离的虚拟环境中运行命令;命令列在命令设置下。
- 将每个环境的结果返回给用户。
这些步骤进一步表明, tox 是一个有效的开发工具,可以通过创建虚拟环境并在其中运行命令来自动化工作流。由于您可以传递给 tox 的命令不限于执行测试的命令,因此 tox 不仅仅是标准化和自动化测试的工具。
tox 的好处
本节重点介绍了使用 tox 管理虚拟环境和自动化工作流(包括测试)的一些好处。
简化协作
每次我接到工作面试的带回家任务时,我都会使用 tox 。为了访问任务,招聘公司的开发人员只需要安装并运行 tox 。与团队合作时也是如此。团队成员不需要复制环境或安装依赖项。所有这些任务都在tox.ini文件中处理。
促进持续集成
如果没有 tox ,您的持续集成( CI )脚本必须同时处理虚拟环境的创建和包依赖项的安装。这意味着没有 tox 构建的 CI 脚本更加复杂。下文将对此进行更详细的探讨。
降低依赖关系冲突的风险
对于每个任务, tox 都会创建一个新的虚拟环境。这减少了依赖冲突的机会。例如,运行应用程序和执行应用程序所需的依赖项可以分别安装到两个独立的虚拟环境中。
Tox 学的一个主要弱点出现在当地发展过程中;也就是说,它无法跟踪依赖关系的变化。因此,每次进行更改时,都必须重新创建毒性环境。这是通过在执行 tox 时传递-r标志来完成的(py -m tox -r)。
简单的 tox 用例示例
为了掌握 tox ,我创建了一个简单的示例,您可以从 kurtispykes/tox_example GitHub 存储库中克隆。跟随学习如何使用 tox 。
├── __init__.py
├── .gitignore
├── LICENSE
├── README.md
├── string_reversal.py
├── test_string_reversal.py
├── tox.ini
tox 生态系统的中心是配置文件,它可能有以下三种风格之一:
tox.ini
setup.cfg
pyproject.toml
本例使用tox.ini配置 tox 。内容如下:
[tox]
envlist = my_env
skipsdist = true
[testenv]
deps = pytest
commands = pytest
INI File Structure 指出,使用.ini扩展名的配置文件“由部分组成,每个部分由[section]标头开头,后跟由特定字符串分隔的键/值条目(默认情况下为=或:)。”
在 tox 中,节标题转换为新的 tox 环境。但是,请注意本例中的[tox]标头。标头配置 tox 运行的全局设置。您可以告诉 tox 使用不同版本的 Python 来执行此标头中的测试。
[tox]标题包含两项:
envlist–通知 tox 从命令行运行py -m tox时要执行的环境。在本例中,envlist被命名为my_env。在最初的 tox 运行之后,其他运行将执行得更快,因为 tox 会跟踪虚拟环境的详细信息,不会重新创建或重新安装依赖项。skipsdist–当没有setup.py或pyproject.toml时,将skipsdist标志设置为真。如果未设置,将导致错误。
请注意,您还可以通过添加要测试的版本( py27 , py37 ),根据不同版本的 Python 测试包。您必须在您的环境中安装要测试包的 Python 版本,否则将引发错误。
[testenv]和[testenv:NAME]标头用于定义 tox 的测试环境,其中NAME是特定环境的名称。[testenv]中定义的设置(称为顶层)将由各个环境自动继承,除非您覆盖这些设置。
本示例不定义单个环境,但设置了以下两项:
deps–执行代码所需的依赖项。commands–作为当前测试环境的一部分要触发的命令。
现在定义了配置,您可以创建并测试一个模块来演示 tox 的作用。为本示例创建的模块是string_reversal.py,其中包含用于反转字符串的函数。
# The contents of string_reversal.py
def reverse_string(text):
reverse_text = text[::-1]
return reverse_text
要测试模块是否正常工作,请使用以下test_string_reversal.py脚本:
# The contents of test_string_reversal.py
from string_reversal import reverse_string
def test_calculate_age():
# Given
text = "Hello World!"
# When
reversed = reverse_string(text)
# Then
assert reversed == "!dlroW olleH"
下一步是从存储tox.ini文件的同一目录运行 tox 。在命令行中,使用以下命令运行 tox :
py -m to
输出应该类似于图 2 所示。
虽然本示例使用 Pytest ,但您可以使用任何其他库来测试模块。事实上,您可以执行任意命令。
创建机器学习包
您还可以将 tox 扩展到各种场景。例如, machine learning ( ML )模型基于交易数据进行训练,以预测欺诈交易何时发生。请参阅 kurtispykes/fraud-detection-project GitHub repo 中的完整代码。 ML 模型包的顶层结构如下所示:
├── fraud_detection_model # Contains the code required to build the model
├── requirements
│ ├── requirements.txt
│ ├── test_requirements.txt
├── tests # Contains the unit tests for the model
├── LICENSE
├── MANIFEST.in
├── mypy.ini
├── publish_model.sh
├── pyproject.toml
├── setup.py
├── tox.ini
构建这个 ML 模型包需要几个依赖项。要更好地管理包依赖关系,请创建requirements.txt文件。
这个项目的 tox 配置文件包括几个可以运行 tox 的环境。这些单独的环境从获取模型训练所需的数据到将训练后的模型发布到 Gemfury 存储库。这进一步表明, tox 可以是管理虚拟环境的有用工具。tox.ini文件中的一些配置如下所示。
# Part of the tox.ini file; click on the GitHub link to view the entire file
[tox]
envlist = test_package, typechecks, stylechecks, lint
skipsdist = True
[testenv]
install_command = pip install {opts} {packages}
passenv =
KAGGLE_USERNAME
KAGGLE_KEY
GEMFURY_PUSH_URL
[testenv:test_package]
deps =
-rrequirements/test_requirements.txt
setenv =
PYTHONPATH=.
PYTHONHASHSEED=0
commands=
python fraud_detection_model/train_pipeline.py
pytest \
-s \
-vv \
{posargs:tests/}
[testenv:train]
envdir = {toxworkdir}/test_package
deps =
{[testenv:test_package]deps}
setenv =
{[testenv:test_package]setenv}
commands=
python fraud_detection_model/train_pipeline.py
[testenv:fetch_data]
envdir = {toxworkdir}/test_package
setenv = {[testenv:test_package]setenv}
commands =
# fetch
kaggle competitions download -c ieee-fraud-detection -p ./fraud_detection_model/data/interim
# unzip
unzip ./fraud_detection_model/data/interim/ieee-fraud-detection.zip -d ./fraud_detection_model/data/interim
[testenv:publish_model]
envdir = {toxworkdir}/test_package
deps =
{[testenv:test_package]deps}
setenv =
{[testenv:test_package]setenv}
commands=
python fraud_detection_model/train_pipeline.py
./publish_model.sh .
请注意,由于添加了setup.py文件,因此skipsdist参数可以从全局 tox 标头中删除。在这种情况下,它没有被删除,因为在打包模型之前, tox 仍然被用于管理虚拟环境。
您可能会注意到,全局envlist(在[tox]标头中)调用test_package、typechecks、stylechecks、lint。当从命令行调用py -m tox时,将创建每个环境,并执行每个环境中的命令。
要选择独立运行的特定环境,请使用以下命令:框架的全部功能。相反,最好将 tox 视为自动化某些工作流和管理虚拟环境的工具。
py -m tox -e NAME
NAME是您希望 tox 创建的testenv的名称。
生产中使用 tox 的注意事项
各种 CI 平台与 tox 集成得非常好。 ML 模型示例使用 CircleCI 进行连续集成。 Circle CI 配置文件调用 tox ,而不是直接创建多个虚拟环境。有关详细信息,请参阅 GitHub 上的 CircleCI configuration file 。
总结
这篇文章解释了如何使用 tox 来实现 Python 中的标准化和自动化测试。仅将 tox 用于自动化测试严重未充分利用框架的全部功能。相反,最好将 tox 视为自动化某些工作流和管理虚拟环境的工具。
Register for NVIDIA GTC 2023 for free , 3 月 20 日至 23 日加入 learn more about data science ,了解加速计算如何改变您的工作。