官网:
https://docs.pytest.org/en/6.2.x/
一、介绍:
灵活简单
参数化
可扩展,
大量运用装饰器
二、入门
1.基础
默认 test_*.py命名,可以在配置文件中进行修改
第三方下载:pip install pytest
查看:pytest --version
执行: 无入口函数,需要pytest解释器 或者添加main入口函数
常用命令参数:
pytest --help:看帮助文档都有介绍说明
pytest -k:** 执行选中的用例
pytest -x 遇到失败的用例就停止执行
pytest -m 标记
2.框架结构
3.参数化
测试数据放在单独文件中,常用yaml.js等,以yaml为例:
add:
positive:
argnames: a,b,expect
argvalues:
- [1,1,2]
- [0.1,0.2,0.3]
- [-3,-5,-8]
- [99999,1,100000]
- [1,-3,-2]
- [2,0.3,2.3]
- [2.4,-4,-1.6]
- [100000,0.1,99999.9]
ids:
- int
- float
- negative
- bignum
- int&negative
- int&float
- float&negative
- bignum&negative
测试代码中打开数据文件,并读取
import pytest
from pythoncode.caclulator import caculator
import yaml
def getdata(name):
with open(".\datas.yaml") as f:
data = yaml.safe_load(f)
return data[name]
def test_data():
print(getdata('add')['positive'])
使用装饰器进行参数化:
@pytest.mark.parametrize(getdata('add')['positive']['argvalues'],ids=getdata('add')['positive']['ids'])
def test_positive_add(self,a,b,expect):
assert expect==self.calcu.add(a,b)
三、进阶
Windows: pytest --help
pytest --help | findstr ** 其中**代表要直接查找的东西
1、数据驱动
以数据更改来推进测试 创建conftest.py,实现数据共享,不需要导入,跨按文件共享
2、fixture
fixture 结合scope和yield发挥和setup teardown的作用 应用场景:
场景: 测试⽤例执⾏时,有的⽤例需要登陆才能执⾏,有些⽤例不需要登陆。setup 和 teardown ⽆法满⾜。fixture 可以。默认 scope(范围)function 步骤:
1.导⼊ pytest
2.在登陆的函数上⾯加@pytest.fixture()
3.在要使⽤的测试⽅法中传⼊(登陆函数名称),就先登陆
4.不传⼊的就不登陆直接执⾏测试⽅法。
场景: 你与其他测试⼯程师合作⼀起开发时,公共的模块要在不同⽂件中,要在⼤家都访问到的地⽅。 解决: 使⽤ conftest.py 这个⽂件进⾏数据共享,并且他可以放在不同位置起着不同的范围共享作⽤。 前提: conftest ⽂件名是不能换的
放在项⽬下是全局的数据共享的地⽅ 执⾏: 系统执⾏到参数 login 时先从本模块中查找是否有这个名字的变量什么的, 之后在
conftest.py 中找是否有。 步骤: 将登陆模块带@pytest.fixture 写在 conftest.py
场景: 不想原测试⽅法有任何改动,或全部都⾃动实现⾃动应⽤,没特例,也都不需要返回值时可以选择⾃动应⽤解决: 使⽤ fixture 中参数 autouse=True 实现 步骤: 在⽅法上⾯加
@pytest.fixture(autouse=True)
场景: 你已经可以将测试⽅法前要执⾏的或依赖的解决了,测试⽅法后销毁清除数据的要如何进⾏呢?范围是模块级别的。类似 setupClass
解决: 通过在同⼀模块中加⼊ yield 关键字,yield 是调⽤第⼀次返回结果,第⼆次执⾏它下⾯的语句返回。
步骤: 在@pytest.fixture(scope=module)。在登陆的⽅法中加 yield,之后加销毁清除的步骤
场景:
测试离不开数据,为了数据灵活,⼀般数据都是通过参数传的解决: fixture 通过固定参数 request 传递
步骤:
在 fixture 中增加@pytest.fixture(params=[1, 2, 3, ‘linda’])
在⽅法参数写request,方法体里面使用 request.param 接收参数
基本应用:
测试步骤加上fixture,测试中需要调用该步骤时,直接将函数名当作参数传递
@pytest.fixture(scope='module')
def login():
print("test login")
yield "token"
# 类似于teardown,
print("log out")
def test_login(login):
# 多个步骤,直接当作参数,逗号隔开传入即可
pass
执行结果:
============================= test session starts =============================
collecting ... collected 1 item
test_fixture.py::test_login test login
PASSED [100%]log out
============================== 1 passed in 0.07s ==============================
参数传递:
import pytest
@pytest.fixture(scope='class',params=['1', '2', '3'],ids=['name1','name2','name3'])
def login(request):
# request是一个内置装饰器,用于传递数据
myparam=request.param
print(f"登录用户名:{myparam}")
return myparam
def test_login(login):
print(login)
3、pytest插件应用
pip install pytest-ordering 控制用例的执行顺序
pip install pytest-xdist 分布式并发执行测试用例:用例之间需要独立,无顺序
pip install pytest-dependency 控制用例的依赖关系
pip install pytest-rerunfailures 失败重跑
pip install pytest-assume 多重较验:想要的结果都断言,多条
pip install pytest-random-order 用例随机执行
pip intall pytest-html 测试报告
注意:多个插件装饰器(>2)的时候,有可能会发生冲突
场景举例:
场景:(用例信赖 )
比如用例 A(添加购物车),用例 B(去结算),如果测试用例 A 运行失败了,执行用例 B
的时候可能也会失败,而且也没有必要运行。 设置用例间依赖关系一旦 A 失败,B 也不会被执行。解决:
https://pytest-dependency.readthedocs.io/en/latest/usage.html#basic-usage安装 pip install pytest-dependency
用法 :
@pytest.mark.dependency(name=‘cart’)
@pytest.mark.dependency(depends=[“cart”])
4、allure生成报告
allure配置:
https://repo1.maven.org/maven2/io/qameta/allure/allure-commandline/
支持多种语言,框架
安装:pip install allure-pytest
生成测试结果:pytest --alluredir=./report/
展示报告:allure serve ./report
生成最终版本的报告:allure generate ./report
(生成html文件,双击无法打开,需要启动服务打开或者部署在jenknis)
布署报告:本地搭建一个网站服务(例如:Django) python manage.py runserver (http://127.0.0.1:8000/)
常用特性:
1、
场景:报告中看到测试功能,子功能或场景,测试步骤,以及附加信息
步骤:功能上加:
@allure.feature(‘功能名’)、@allure.story(‘子功能名’)、@allure.step(‘步骤名’)、@allure.attach(‘具体文本信息:数据,文本,图片,视频,网页’)
运行:pytest ** --allure-story=“名字” -vs --alluredir=./report/
2、关联测试用例
@allure.testcase(link,"test case title")
3、重要级别分类
allure.severity:(trivial<minor<normal<critical<blocker)
步骤:方法函数或类上加装饰器@allure.severity(allure.severity_level.trivial)
执行:
pytest name --allure-serverities normal,trivial
5、打印日志
在pytest.ini中配置:
[pytest]
log_cli = true
log_cli_level = info
addopts = --capture=no
log_cli_format = %(asctime)s [%(levelname)s] %(message)s (%(filename)s:%(lineno)s)
log_cli_date_format = %Y-%m-%d %H:%M:%S
log_file = ../logs/run.log
log_file_level = info
log_file_format = %(asctime)s [%(levelname)s] %(message)s (%(filename)s:%(lineno)s)
log_file_date_format = %Y-%m-%d %H:%M:%S
testpaths = tests