转载自 https://blog.csdn.net/liuchunming033/article/details/46501653
pytest 单元测试框架
pytest 是python的一种单元测试框架,与python自带的unitest测试类似,但是比 unittest 更简洁、效率更高。根据pytest官方的介绍,它具有以下特点:
- 非常容易上手,入门简单、文档丰富
- 能够支持简单的单元测试复杂的功能测试
- 支持参数化
- 执行测试过程中可以将某测试跳过,或者对某些预期失败的case标记成失败
- 支持重复执行失败的case
- 支持运行由nose, unittest编写的测试case
- 具有很多第三方插件,并且可以自定义扩展
- 方便的和持续集成工具集成
安装
pip install pytest
# 确认
(sysadmin-Cc_I1K2h) D:\projects\pythoncode\sysadmin>py.test --version
This is pytest version 4.6.3, imported from c:\users\lite\.virtualenvs\sysadmin-cc_i1k2h\lib\site-packages\pytest.py
定义实例
我们可以通过下面的实例,看看使用py.test进行测试是多么简单。
- filename test_xxxx.py
- 测试函数 test_xxxx()
# content of test_sample.py
def func(x):
return x+1
def test_func():
assert func(3) == 5
这里我们定义了一个被测试函数func,该函数将传递进来的参数加1后返回。我们还定义了一个测试函数 test_func用来对func进行测试。test_func中我们使用基本的断言语言assert来对结果进行验证。
下面来运行这个测试
$ pytest
=========================== test session starts ============================
platform linux -- Python 3.4.1 -- py-1.4.27 -- pytest-2.7.1
rootdir: /tmp/doc-exec-101, inifile:
collected 1 items
test_sample.py F
================================= FAILURES =================================
_______________________________ test_answer ________________________________
def test_answer():
> assert func(3) == 5
E assert 4 == 5
E + where 4 = func(3)
test_sample.py:5: AssertionError
========================= 1 failed in 0.01 seconds =========================
执行测试
执行测试的时候,我们只需要在测试文件test_sample所在的目录下,运行py.test即可。
pytest会在当前的目录下,寻找以test开头的文件(即测试文件),找到测试文件之后,进入到测试文件中寻找test_开头的测试函数并执行。
通过上面的测试输出,我们可以看到该测试过程中,一个收集到了一个测试函数,测试结果是失败的(标记为F),并且在FAILURES部分输出了详细的错误信息,帮助我们分析测试原因,我们可以看到”assert func(3) == 5”这条语句出错了,错误的原因是func(3)=4,然后我们断言func(3) 等于 5。
多个测试
当需要编写多个测试样例的时候,我们可以将其放到一个测试类当中,如:
# content of test_class.py
class TestClass:
def test_one(self):
x = "this"
assert 'h' in x
def test_two(self):
x = "hello"
assert hasattr(x, 'check')
我们可以通过执行测试文件的方法,执行上面的测试:
$ pytest -q test_class.py
.F
================================= FAILURES =================================
____________________________ TestClass.test_two ____________________________
self = <test_class.TestClass object at 0x7fbf54cf5668>
def test_two(self):
x = "hello"
> assert hasattr(x, 'check')
E assert hasattr('hello', 'check')
test_class.py:8: AssertionError
1 failed, 1 passed in 0.01 seconds
从测试结果中可以看到,该测试共执行了两个测试样例,一个失败一个成功。同样,我们也看到失败样例的详细信息,和执行过程中的中间结果。
如何编写测试要样例
通过上面2个实例,我们发现编写pytest测试样例非常简单,只需要按照下面的规则:
- 测试文件以test_开头(以_test结尾也可以)
- 测试类以Test开头,并且不能带有 init 方法
- 测试函数以test_开头
- 断言使用基本的assert即可
如何执行测试样例
执行测试样例的方法很多种,上面第一个实例是直接执行py.test,第二个实例是传递了测试文件给py.test。其实py.test有好多种方法执行测试:
pytest # run all tests below current dir
pytest test_mod.py # run tests in module
pytest somepath # run all tests below somepath
pytest -k stringexpr # only run tests with names that match the
# the "string expression", e.g. "MyClass and not method"
# will select TestMyClass.test_something
# but not TestMyClass.test_method_simple
pytest test_mod.py::test_func # only run tests that match the "node ID",
# e.g "test_mod.py::test_func" will select
# only test_func in test_mod.py
测试报告
pytest可以方便的生成测试报告,即可以生成HTML的测试报告,也可以生成XML格式的测试报告用来与持续集成工具集成。
生成HTML格式报告:
pytest --resultlog=path
生成XML格式的报告:
pytest --junitxml=path
获取帮助信息
pytest --version # shows where pytest was imported from
pytest --fixtures # show available builtin function arguments
pytest -h | --help # show help on command line and config file options
最佳实践
其实对于测试而言,特别是在持续集成环境中,我们的所有测试最好是在虚拟环境中。这样不同的虚拟环境中的测试不会相互干扰的。
由于我们的实际工作中,在同一个Jekins中,运行了好多种不同项目册的测试,因此,各个测试项目运行在各自的虚拟环境中。
将pytest安装在虚拟环境中:1、将当前目录创建为虚拟环境
virtualenv . # create a virtualenv directory in the current directory
source bin/activate # on unix
2、在虚拟环境中安装pytest:
pip install pytest
使用 pipenv
$ pipenv install pytest --dev
pytest-fixture
fixture
fixture是在测试函数运行前后,由pytest执行的外壳函数;
代码可以定制,满足多变的测试需求
- 定义传入测试中的数据集,
- 配置测试前系统的初始状态
- 为批量测试提供数据源等
fixture是用于将测试胶后进行预备,清理工作的代码分离出核心测试逻辑。
用于分离 测试前后的准备工作与测试核心逻辑
检测顺序:优先搜索该测试所在模块, 然后搜索 conftest.py
放置位置
- 测试所在模块
- 当前目录 conftest.py 文件
集成的项目
https://github.com/amisadmin/fastapi_amis_admin
https://github.com/aminalaee/sqladmin
https://github.com/laixintao/iredis