python-pytest使用
大纲:
- 安装
- 简单实例
- 执行过程
- 利用pytest实现setUp/teardown
- 其他
- 接入报告
安装
pip install -U pytest
检测:pytest --version
简单实例
case文件规范:test_*.py
case规范:可以直接是方法,而非unittest这种需要case为类;当然pytest是支持unittest的case(类不需要继承);方法需要以test*结构
使用:pytest -q 文件/pytest
断言:直接使用assert
#test_case.py
import pytest
def fun(x):
return x+1
def test_1():
assert fun(3)==4
执行过程:pytest模块会先找项目文件中test_*.py/*_test.py的文件;然后会从文件中找test*的方法/类,如果case方法中有内置参数,在去 conftest.py配置文件中查找@pytest.fixture(mondle/class/fucntion):定义的内置方法/类,在将该定义的方法作为参数传递入case方法中
@pytest.fixture(mondle/class/fucntion):其中@
pytest.fixture装饰器定义的方法/类类似setUp/teardown定义的方法;然后
mondle/class/fucntion表示方法的作用范围
pytest --fixtures
查找内置的固定装置:
利用pytest实现setUp/teardown实例:
在pytest中进行前后置操作,主要是通过固件(fixture)来实现的;下面介绍下固件:
是什么:
- 固件本质上是一个函数,能在执行待测对象进行时进行前置和后置的操作;在固件函数中,yield前的是进行前置操作的,yield后的是进行后置操作的;
怎么样:
- 使用@pytest.fixture()装饰器来定义;可直接放置在待测脚本中,为了复用,也可新建一个
conftest.py
文件来进行集中管理固件 - 作用范围:
conftest.py文件所在目录,及其子目录
- 常用参数有三个:别名/作用域/是否自动执行
- @pytest.fixture(foo="f") //f是固件函数的别名
- @pytest.fixture(foo="f",scope='class') //scope属性定义了作用域的范围;共有四个可选值如下,默认为函数级:
function
: 函数级,每个测试函数都会执行一次固件;class
: 类级别,每个测试类执行一次,所有方法都可以使用;module
: 模块级,每个模块执行一次,模块内函数和方法都可使用;session
: 会话级,一次测试只执行一次,所有被找到的函数和方法都可用@pytest.fixture(scope='function')
def func_scope():
pass
@pytest.fixture(scope='module')
def mod_scope():
pass
@pytest.fixture(scope='session')
def sess_scope():
pass
@pytest.fixture(scope='class')
def class_scope():
pass
-
-
是否自动执行:pytest.fixture(foo="f",scope='class',autouse=True);如果不自动执行,最方便的是将作用域作为参数传递到待测函数
-
细致跟踪固件执行,可以使用
--setup-show
选项:pytest --setup-show tests/fixture/test_scope.py::test_multi_scope
-
使用固件方法1:直接作为参数引入/配置自动执行
-
def test_multi_scope(sess_scope, mod_scope, func_scope): pass
-
- 使用固件方法2:使用pytest.mark.usefixture
- 使用固件方法2:定义固件时,自动配置自动执行
@pytest.fixture(scope='class') def class_scope(): pass
-
@pytest.mark.usefixtures('class_scope') class TestClassScope: def test_1(self): pass def test_2(self): pass
-
#conftest.py的内容
import pytest
@pytest.fixture(foo='f',scope="function",autouse=True)
def foo():
print(" function setup")
yield 100 #yield前的是前置操作,后的是后置操作
print(" function teardown")
#test_1540.py的内容
import pytest
def inc(x):
return x + 1
def test_answer_1():
assert inc(3) == 5
def test_answer_2(foo):
print(foo)
assert inc(98) == foo
if __name__ == '__main__':
pytest.main()
运行pytest
- python -m pytest test_*.py
- pytest test_*.py
- pytest testing/ #运行路径下的所有文件作为case
- pytest -k "MyClass and not method" #运行文件名/类名/方法中含case的对象
- pytest test_mod.py::TestClass::test_method #按节点id来运行case;由于pytest收集的测试集,每个case都有一个固定的nodeid,结构就是文件名::类名::方法名,因此可通过这种方法来调用
- pytest --pyargs pkg.testing==pytest testing/ 从包运行
- pytest -m slow #通过标记表达式运行,将运行用
@pytest.mark.slow
装饰器装饰的所有测试。 - pytest --trace #进入python调试器
- pytest --durations=10 --durations-min=1.0 #显示1s内最慢的10个执行case
- pytest --junitxml=path #生成可被jenkin读取的配置文件,如要以该配置文件运行可在下方结构中配置
[pytest] junit_suite_name = my_suite(xml配置名称)
- 在python代码中运行pytest的case:
pytest.main()#由于python导入的缓存机制,因此不建议在一个程序中使用多次该调用/pytest.main(["-x", "mytestdir"])#传递选项和参数 /pytest.main(["-x", "mytestdir"])
运行pytest会导致六个不同的退出代码:
退出码0
所有测试均已收集并成功通过
退出代码1
测试已收集并运行,但有些测试失败
退出代码2
测试执行被用户中断
退出代码3
执行测试时发生内部错误
退出代码4
pytest命令行用法错误
退出代码5
没有收集测试
有时需要对运行状态进行判断,此时需要用到退出码参数,需要先导入:
from pytest import ExitCode
其他命令:pytest -h查看环境变量/pytest --help帮助信息/pytest --fixtures查看内置的固定结构
运行case失败后停止:
pytest -x # stop after first failure(1个case失败停止)
pytest --maxfail=2 # stop after two failures
接入报告
pytest和其他的测试套件一起使用
如nose/unittest
cd <repository>
pip install -e . # Environment dependent alternatives include
# 'python setup.py develop' and 'conda develop'