- pytest介绍
- pytest测试用例的识别与运行
- 参数解析
- pytest实战
- pytest是一个非常强大的Python测试框架
- 可以支持参数化
- 测试用例的skip和xfail,自动失败重试等等处理
- 能够支持简单的单元测试和复杂的功能测试,还可以用来做selenium/appnium等自动化测试,接口自动化测试(pytest+requests);
- pytest具有很多第三方插件,支持自定义扩展,pytest-allure测试报告,pytest-xdist 多cpu分发等等
- 也可以结合jenkins集成
pytest官方文档:https://docs.pytest.org/en/latest/contents.html#toc
库下载地址:https://pypi.org/search/?q=pytest
安装pytest模块pip install -U pytest查看pytest 版本号
(如有输出结果,则安装成功)
$ pytest --version pytest 6.2.5执行用例
test_sample.py
def func(x):
return x + 1
def test_1():
assert func(3) == 5
pytest .test_sample.pypytest安装与依赖
pip install -U pytest U为升级 pip install pytest-sugar pip install pytest-rerunfailures pip install pytest-xdist pip install pytest-assume pip install pytest-html pip list 查看 pytest -h 帮助pytest测试用例的识别与运行 测试文件
test_*.py
*_test.py
用例识别Test*类包含的所有test_*的方法(测试类不能带有__init__方法)
不在class中的所有的test_*方法
pytest也可以执行unittest框架写的用例和方法 cmd命令执行pytest test.py 执行测试用例 pytest -v (最高级别信息--verbose) 打印详细运行日志信息 pytest -v -s 文件名 (s是带控制台输出的结果,也是输出详细) pytest 文件名.py 执行单独一个pytest模块 pytest 文件名.py::类名 运行某个模块里面的某个类 pytest 文件名.py::类名::方法名 运行某个模块里面某个类里面的方法 pytest -v -k "类名 and not 方法名" 跳过运行某个用例 pytest -m[标记名] @pytest.mark.[标记名将运行有这个标记的测试用例] pytest -x 文件名 运行报错就停止运行 pytest --maxfail=[num] 当运行错误达到num的时候就停止运行pytest测试用例失败后重新执行 安装pytest-rerunfailures模块
pip install pytest-rerunfailures1,用例执行失败,重新执行次数,
pytest --reruns 5 test_1.py2,间隔执行用例时间
pytest --reruns 5 --reruns-delay 1 test_1.pypytest断言失败继续执行 安装pytest-assume模块
pip install pytest-assumepytest结构顺序
1,模块setup_module/teardown_module 模块始末,全局(优先级最高)
2,函数setup_function/teardown_function 只对函数用例生效(不在类中)
3,类setup_class/teardown_class 只在类中前后运行(在类中)
4,方法级setup_method/teardown_methond 开始于方法始末(在类中)
5,类里面setup/teardown 运行在调用方法的前后
pytest fixture有的用例需要登录,有的不需要,fixture可以解决这个问题
import pytest
@pytest.fixture()
def test_login():
print('登录')
def test_case01(test_login):
print('登录成功')
pass
def test_case02():
print('不用登录,也可以访问')
pass
def test_case03(test_login):
print('登录成功')
pass
if __name__ == '__main__':
pytest.main()
公共文件-conftest
conftest.py 配置需要注意
conftest文件名是不能换的
conftest.py与运行的用例要在同一个package下,要有__init__.py文件
不需要import导入conftest.py pytest用例会自动查找
conftest.py是全局的配置,数据共享的地方
pytest yieldimport pytest
@pytest.fixture(scope="module")
def test_login():
print('登录')
yield
def test_case01(test_login):
print('case1 ok')
pass
def test_case02(test_login):
print('case2 ok')
pass
if __name__ == '__main__':
pytest.main(["-s","-v",r"E:pythoncodepython_testtest_sample.py"])
pytest parametrize参数化
import pytest
@pytest.mark.parametrize("test_input,expected",[("3+5",8),("2+5",7),("7+5",30)])
def test_eval(test_input,expected):
assert eval(test_input) == expected
if __name__ == '__main__':
pytest.main(["-s","-v",r"E:pythoncodepython_testtest_sample.py"])
pytest xfail标记失败错误的用例
import pytest
@pytest.mark.parametrize("test_input,expected",[("3+5",8),("2+5",7),("7+5",30)])
def test_eval(test_input,expected):
assert eval(test_input) == expected
@pytest.mark.xfail
def test_case01():
a=0
assert a != "0"
raise NameError()
if __name__ == '__main__':
pytest.main(["-s","-v",r"E:pythoncodepython_testtest_sample.py"])
pytest skip跳过测试用例
import pytest
@pytest.mark.parametrize("test_input,expected",[("3+5",8),("2+5",7),("7+5",30)])
def test_eval(test_input,expected):
assert eval(test_input) == expected
@pytest.mark.xfail(reason="这条用例执行会失败")
def test_case01():
a=0
assert a != "0"
raise NameError()
@pytest.mark.skip(reason="这条用例不执行")
def test_case02():
a=0
assert a != "0"
def test_case03():
a=0
assert a == 0
if __name__ == '__main__':
pytest.main(["-s","-v",r"E:pythoncodepython_testtest_sample.py"])
mark中的skip与xfail
skip:
- 不想运行某个测试用例
- 标记无法执行的测试用例
- @pytest.mark.skip跳过测试用例,也可以加条件skipif,在满足某些条件才能通过,否则跳过这个测试用例
xfail
- 标记预计失败的测试用例
- 标记某个测试用例的预期结果就是要失败
-s 输出所有测试用的print信息 -m 执行自定义标记的相关用例 pytest -s test_01.py pytest -s test_01.py -m=webtest pytest -s test_01.py -m apptest pytest -s test_01.py -m "not ios"多线程并行和分布式执行测试用例
- 安装 pytest-xdist库
pip install pytest-xdist
- 多个cpu并行执行用例,-n 3 是并行数量 pytest -n 3
- 在多给终端执行
import pytest
@pytest.mark.parametrize("test_input,expected",[("3+5",8),("2+5",7),("7+5",30)])
def test_eval(test_input,expected):
assert eval(test_input) == expected
@pytest.mark.xfail(reason="这条用例执行会失败")
def test_case01():
a=0
assert a != "0"
raise NameError()
@pytest.mark.skip(reason="这条用例不执行")
def test_case02():
a=0
assert a != "0"
def test_case03():
a=0
assert a == 0
if __name__ == '__main__':
pytest.main(["-n 3","-s","-v",r"E:pythoncodepython_testtest_sample.py"])
ps:测试用例数量多才能看到明显的执行速度
pytest-html 生成测试报告 安装 pytest-html 库pip install pytest-html生成html测试报告
pytest -v -s --html=report.html --self-contained-html
import pytest
@pytest.mark.parametrize("test_input,expected",[("3+5",8),("2+5",7),("7+5",30)])
def test_eval(test_input,expected):
assert eval(test_input) == expected
@pytest.mark.xfail(reason="这条用例执行会失败")
def test_case01():
a=0
assert a != "0"
raise NameError()
@pytest.mark.skip(reason="这条用例不执行")
def test_case02():
a=0
assert a != "0"
def test_case03():
a=0
assert a == 0
if __name__ == '__main__':
pytest.main(["-n 3","-s","-v",r"E:pythoncodepython_testtest_sample.py","--html=report.html","--self-contained-html"])



