Pytest使用简介
Pytest是一种基于python的测试框架,用于编写和运行测试代码。pytest主要用来测试API,但也可以进行一些复杂的测试,像测试数据库或UI等。
Pytest 的优势:
- Pytest 可以并行执行多个tests, 减少 test-suite 的执行时间 [第八章]
- Pytest 可以自动地检测测试文件或测试函数,不需要被显示地提及 [第二章]
- test_*.py 文件
- *_test.py 文件
- test* 函数
- Pytest 允许我们在运行过程中跳过一些test,执行整个test-suite的子集 [第三,四,五,六章]
- Pytest 免费开源,易学
(一)pytest 安装
安装 pytest: pip3 install pytest
查看 pytest 是否安装成功:pip3 show pytest
若安装成功,将会有如下显示
Name: pytest
Version: 5.3.5
Summary: pytest: simple powerful testing with Python
Home-page: https://docs.pytest.org/en/latest/
Author: Holger Krekel, Bruno Oliveira, Ronny Pfannschmidt, Floris Bruynooghe, Brianna Laugher, Florian Bruhin and others
Author-email: None
License: MIT license
Location: /usr/local/lib/python3.7/site-packages
Requires: pluggy, py, importlib-metadata, more-itertools, wcwidth, attrs, packaging
Required-by:
(二)Pytest 测试文件/函数
2.1. Pytest 测试文件:Pytest命令会自动运行当前目录下所有' test_*.py' 和 '_test.py' 文件 [1], 自动默认这些文件是测试文件。当然,我们也可以显示地指示要要运行的测试文件或测试目录。
Running pytest without mentioning a filename will run all files of format test_*.py or *_test.py in the current directory and subdirectories. Pytest automatically identifies those files as test files. We can make pytest run other filenames by explicitly mentioning them.
pytest a.py
pytest dirname
2.2. Pytest 测试函数:Pytest需要被测试函数以‘test’开头命名,不以'test' 开头的函数会被pytest自动忽略,pytest不可以像指定文件一样显示地指定被测函数,即测试函数必须以'test'开头。
Pytest requires the test function names to start with test. Function names which are not of format test* are not considered as test functions by pytest. We cannot explicitly make pytest consider any function not starting with test as a test function.
【例子1】创建Pytest文件夹,新建文件 test_nn.py 和 test_greater.py 和 test.py. 目录结构如下
Pytest
|- test.py
|- test_great.py: test_greater(); test_greater_equal(); test_less();
|- test_nn.py: testx(); test_great_haha();
运行 pytest 命令,只显示 test_great.py 和 test_nn.py 文件,因为[1],其中 test_great.py 代码如下
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def test_greater(): num = 100 assert num > 100 def test_greater_equal(): num = 100 assert num >= 100 def test_less(): num = 100 assert num < 200
运行pytest 和 pytest -v 命令,运行结果分别如下左右图所示,-v 显示更
(三)Pytest 可以选择性测试完整test-suite的某个子集(subset)
3.1. 依照文件名匹配的方式选择测试子集 (select tests to run based on substring matching of test names)
pytest -k <substring> -v
针对【例子1】
pytest -k great -v 命令 ('great' 对应 <substring>项) 执行所有带有great的测试,
注意:pytest -k 'substring' -v: 可识别当前目录下所有匹配文件中带有 ‘substring’ 的测试函数。
3.2. 根据 标记 选择测试组进行测试 (select tests groups to run based on the markers applied)
添加相关包:import pytest
插入标记:@pytest.mark.<markname> 运行带标记的测试:pytest -m <markname> -v
[例子2] 带标记 (marker) 的 test_mark.py 文件如下
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import pytest @pytest.mark.great def test_greater(): num = 100 assert num > 100 @pytest.mark.great def test_greater_equal(): num = 100 assert num >= 100 @pytest.mark.others def test_less(): num = 100 assert num < 200
(四)Pytest 通过 Fixture 和 conftest.py 加载测试所需调用
@pytest.fixture
Fixture 是测试的输入,测试被执行前, 涉及到的 fixture 会被执行到。Pytest 提供了 @pytest.fixture 将该部分代码自动附加到测试函数中
【注意】(1) 如果不加 @pytest.fixture 的话,这部分被测试函数调用的代码不会加载进入测试函数,pytest运行时会报错 ...
(2) @pytest.fixture 的作用域是当前文件,在其他文件中调用该 fixture 对应的函数会报错.We cannot use that fixture in another test file
Fixtures are functions, which will run before each test function to which it is applied. Fixtures are used to feed some data to the tests such as database connections, URLs to test and some sort of input data. Therefore, instead of runnng the same code for every test, we can attach fixture to the tests and it will run and return the data to the test before executing each test.
【例子3.1】创建 test_div.py 内容如下
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import pytest @pytest.mark.great def test_greater(): num = 100 assert num > 100 @pytest.mark.great def test_greater_equal(): num = 100 assert num >= 100 @pytest.mark.others def test_less(): num = 100 assert num < 200
为了克服(2)的限制, 在多个测试文件中调用 Fixture, 我们需要 conftest.py 统一定义存储 Fixture
【例子3.2】新建 conftest.py 内容如下
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import pytest @pytest.fixture def input_value(): input = 39 return input
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# content of file 'test_14' def test_divisible_14(input_value): assert input_value%14 ==0 # content of file 'test_15' def test_divisible_15(input_value): assert input_value%15 ==0 # content of file 'test_16' def test_divisible_16(input_value): assert input_value%16 ==0
运行 pytest -k divisible -v 时,由于conftest.py 文件已声明 fixture, 所以input_value() 函数会自动加载到每次调用之前,测试正常进行
(五)Pytest指定测试,验证实际输出和期望输出是否一致
Pytest 用 @pytest.mark.parametrize() 测试指定的<input, output>对
【例子4】添加@pytest.mark.parametrize()子句如下
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import pytest @pytest.mark.parametrize("num,output",[(1,11),(2,22),(3,35),(4,44)]) def test_multiplication_11(num,output): assert 11*num == output
(六)Pytest 跳过某些测试/屏蔽某些测试错
@pytest.mark.skip 用来掉过某些测试
@pytest.mark.xfail 用来屏蔽某些测试的错误
【例子5】新建 test_op.py 文件,内容如下
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import pytest @pytest.mark.xfail @pytest.mark.great def test_greater(): num = 100 assert num > 100 @pytest.mark.great def test_greater_equal(): num = 100 assert num >= 200 @pytest.mark.skip @pytest.mark.others def test_divisible(input_value): assert input_value < 200
运行 pytest test_op.py 运行结果如下,test_greater() 错误被屏蔽,test_greater_equal()正常报错,test_divisible()被测试跳过
(七)Pytest测试停止
cmd: pytest --maxfail = <num>
当检测出的错误个数等于num时,pytest 测试结束,不在对后面的代码进行测试
(八)Pytest 并行测试
pip install pytest-xdist // 安装pytest 并行测试工具
pytest -n <num> // runs in <num> workers
(九)Pytest 将测试结果记录到 xml 文件中
pytest -v --junitxml=<filename>
【例子6】 pytest -v --junitxml="result.xml"
参考(Reference)