在自动测试领域,您可以找到不同的工具,例如py.test是使用Python编写自动测试的最受欢迎的解决方案之一。
在浏览了许多与pytest相关的资源并研究了该项目官方网站上的文档后,我找不到对主要任务之一的解决方案的直接描述-使用存储在单独文件中的测试数据运行测试。 否则,可以说是从文件将参数加载到测试功能中,或者直接从文件中加载参数。 此类程序在复杂性中没有任何地方描述,并且仅在pytest文档的一行中提到了此功能。
在本文中,我将讨论该问题的解决方案。
挑战赛
主要任务是从相应的文件函数名称将test_input
和test_input
参数形式的测试用例生成到每个单独的测试函数中。
其他任务:
- 选择人类可读的带有测试用例的文件格式;
- 保留支持硬编码测试用例的能力;
- 显示每种情况的明确标识符。
工具包
在本文中,我使用了Python 3(也适用于2.7),pyyaml和pytest
(Python 3的版本为5 +,Python 2.7的版本为4.6),而没有使用第三方插件。 另外,将使用标准的os
库。
我们将使用测试用例的文件本身需要使用便于人类理解的标记语言来构造。 在我的情况下,选择了YAML (因为它解决了选择人类可读格式的额外任务) 。 实际上,您需要哪种具有数据集的文件标记语言取决于项目中提出的要求。
实作
由于编程领域的主要支柱是协议,因此我们必须为解决方案引入一些协议。
拦截
首先,此解决方案使用pytest_generate_tests
( wiki )拦截函数(该函数从生成测试用例的阶段开始)及其参数metafunc
,该参数允许我们对该函数进行参数化。 此时,pytest遍历每个测试函数并为其执行后续的生成代码。
争论
您必须为测试功能定义详尽的参数列表。 在我的情况下,字典是test_input
而任何数据类型(通常是字符串或整数)都在test_input
中。 我们需要在metafunc.parametrize(...)
使用这些参数。
参数化
此函数完全重复参数化 @pytest.mark.parametrize
的操作,该操作将第一个参数作为第一个参数,该字符串列出了测试功能的参数(在我们的示例中为"test_input, expected_result"
),并通过数据列表进行迭代以创建我们的测试用例(例如[(1, 2), (2, 4), (3, 6)]
)。
在战斗中,它将如下所示:
@pytest.mark.parametrize("test_input, expected_result", [(1, 2), (2, 4), (3, 6)]) def test_multiplication(test_input, expected_result): assert test_input * 2 == expected_result
在我们的情况下,我们将提前指出:
筛选
从这里还遵循那些测试功能的分配,这些测试功能需要使用文件中的数据,而那些使用静态/动态数据。 我们将在解析文件中的信息之前应用此过滤。
过滤器本身可以是任何过滤器,例如:
否则,可以像这样实现相同的过滤器:
这个选项最适合我。
结果
我们只需要添加解析文件中数据的部分。 对于yaml (以及json,xml等) ,这并不困难,因此我们将所有内容收集到堆中。
我们编写这样的测试脚本:
数据文件:
# test_multiplication.yaml - !!python/tuple [1,2] - !!python/tuple [1,3] - !!python/tuple [1,5] - !!python/tuple [2,4] - !!python/tuple [3,4] - !!python/tuple [5,4]
我们得到以下测试用例列表:
pytest /test_script.py --collect-only ======================== test session starts ======================== platform linux -- Python 3.7.4, pytest-5.2.1, py-1.8.0, pluggy-0.13.0 rootdir: /pytest_habr collected 6 items <Module test_script.py> <Function test_multiplication[1-2]> <Function test_multiplication[1-3]> <Function test_multiplication[1-5]> <Function test_multiplication[2-4]> <Function test_multiplication[3-4]> <Function test_multiplication[5-4]> ======================== no tests ran in 0.04s ========================
通过运行脚本,结果为: 4 failed, 2 passed, 1 warnings in 0.11s
添加。 作业
至此文章可能会结束,但是出于复杂性考虑,我将在函数中添加更多方便的标识符,并对每个测试用例进行另一个数据解析和标记。
因此,代码立即:
因此,我们更改了YAML文件的外观:
# test_multiplication.yaml - test_data: [1, 2] id: 'one_two' - test_data: [1,3] marks: ['xfail'] - test_data: [1,5] marks: ['skip'] - test_data: [2,4] id: "it's good" marks: ['xfail'] - test_data: [3,4] marks: ['negative'] - test_data: [5,4] marks: ['more_than']
然后说明将变为:
<Module test_script.py> <Function test_multiplication[one_two]> <Function test_multiplication[1_3]> <Function test_multiplication[1_5]> <Function test_multiplication[it's good]> <Function test_multiplication[3_4]> <Function test_multiplication[5_4]>
启动将是: 2 failed, 1 passed, 1 skipped, 1 xfailed, 1 xpassed, 2 warnings in 0.12s
PS:警告-因为 自写标记未记录在pytest.ini中
发展中的话题
准备在评论中讨论有关类型的问题:
- 编写Yaml文件的最佳方法是什么?
- 以哪种格式存储测试数据更方便?
- 在生成阶段需要什么其他测试用例?
- 是否需要每种情况的标识符?