单元测试
单元测试是针对特定库或模块的小型独立测试。Ansible 中的单元测试目前是 Ansible 持续集成流程中从 Python 内部驱动测试的唯一方式。这意味着在某些情况下,测试可能比仅仅是单元测试要宽泛一些。
可用测试
可以在 test/units 中找到单元测试。请注意,测试的目录结构与 lib/ansible/
的目录结构一致。
运行测试
注意
要使用 Docker 运行单元测试,请始终使用默认 Docker 镜像,方法是传递 --docker
或 --docker default
参数。
可以通过以下方式运行整个代码库的 Ansible 单元测试
cd /path/to/ansible/source
source hacking/env-setup
ansible-test units --docker -v
针对单个文件,执行以下操作
ansible-test units --docker -v apt
或者针对特定的 Python 版本,执行以下操作
ansible-test units --docker -v --python 2.7 apt
如果您正在针对模块以外的其他内容(例如模块实用程序)运行单元测试,请指定整个文件路径
ansible-test units --docker -v test/units/module_utils/basic/test_imports.py
有关高级用法,请参见联机帮助
ansible-test units --help
您还可以通过打开拉取请求在 Ansible 的持续集成系统中运行测试。这将根据您在拉取请求中所做的更改自动确定要运行的测试。
安装依赖项
如果您使用 --docker
或 --venv
选项运行 ansible-test
,则无需手动安装依赖项。
否则,您可以使用 --requirements
选项安装依赖项,它将安装单元测试所需的全部依赖项。例如
ansible-test units --python 2.7 --requirements apache2_module
可以在 test/units/requirements.txt 中找到单元测试要求的列表。
这并不包括 ansible-test
本身的单元测试要求的列表,该列表可以在 test/lib/ansible_test/_data/requirements/units.txt 中找到。
另请参见适用于所有测试命令的 约束。
扩展单元测试
警告
单元测试不是什么
如果您开始编写需要外部服务的测试,那么您可能是在编写集成测试,而不是单元测试。
构建单元测试
Ansible 通过 pytest 驱动单元测试。这意味着测试可以编写为简单的函数,这些函数包含在任何以 test_<something>.py
结尾的文件中,也可以编写为类。
以下是一个函数的示例
#this function will be called simply because it is called test_*()
def test_add():
a = 10
b = 23
c = 33
assert a + b == c
以下是一个类的示例
import unittest
class AddTester(unittest.TestCase):
def SetUp():
self.a = 10
self.b = 23
# this function will
def test_add():
c = 33
assert self.a + self.b == c
# this function will
def test_subtract():
c = -13
assert self.a - self.b == c
在大多数情况下,两种方法都可以正常工作;基于函数的接口更简单、更快,因此如果您只是想为模块添加一些基本的测试,那么您可能应该从这里开始。基于类的测试允许对先决条件进行更整洁的设置和拆卸,因此如果您有许多针对模块的测试用例,您可能希望重构以使用它。
使用测试中的简单 assert
函数进行断言将提供有关失败原因的完整信息,并提供在断言期间调用的函数的跟踪信息。这意味着建议使用纯断言而不是其他外部断言库。
许多单元测试套件包括在几个模块之间共享的函数,尤其是在网络领域。在这些情况下,会在同一目录中创建一个文件,然后直接包含该文件。
模块测试用例通用代码
在 test/units/ 目录结构中尽可能具体地保留通用代码。不要从当前目录或父目录之外的目录导入通用单元测试代码。
不要从单元测试中导入其他单元测试。任何通用代码都应该位于专门的文件中,这些文件本身不是测试。
夹具文件
要模拟从设备获取结果,或提供来自外部库的其他复杂数据结构,可以使用 fixtures
来读取预生成的数据。
您可以查看 夹具 在 cpuinfo 事实测试 中是如何使用的
如果您正在模拟 API,您可能会发现 Python placebo 很有用。有关更多信息,请参见 对 Ansible 模块进行单元测试。
新单元测试或更新的单元测试的代码覆盖率
新的代码将缺失于 codecov.io 代码覆盖率报告(参见 测试 Ansible)中,因此需要进行本地报告。大多数 ansible-test
命令允许您收集代码覆盖率;这在指示扩展测试的位置时特别有用。
要收集覆盖率数据,请将 --coverage
参数添加到您的 ansible-test
命令行
ansible-test units --coverage apt
ansible-test coverage html
结果将写入 test/results/reports/coverage/index.html
可以使用多种不同的格式生成报告
ansible-test coverage report
- 控制台报告。ansible-test coverage html
- HTML 报告。ansible-test coverage xml
- XML 报告。
要清除测试运行之间的數據,请使用 ansible-test coverage erase
命令。有关生成覆盖率报告的更多信息,请参见 测试 Ansible 和集合。
另请参见
- 对 Ansible 模块进行单元测试
对模块进行单元测试的特殊注意事项
- 测试 Ansible 和集合
在本地运行测试,包括收集和报告覆盖率数据
- Python 3 文档 - 26.4. unittest — 单元测试框架
Python 3 中的 unittest 框架的文档
- Python 2 文档 - 25.3. unittest — 单元测试框架
最早支持的 unittest 框架的文档 - 来自 Python 2.6
- pytest:帮助您编写更好的程序
pytest 的文档 - 实际用于运行 Ansible 单元测试的框架