pytest是python的一种单元测试框架,与python自带的unittest测试框架类似,但是比unittest框架使用起来更简洁,效率更高
a. 特点
- pytest是python当中的一个单元框架,比unittest更灵活
- pytest和selenium,requests,appium结合实现web自动化,接口自动化,app自动化
- pytest可以实现测试用例的跳过以及reruns失败用例重试
- pytest可以和allure生成非常美观的测试报告
- pytest可以和Jenkins持续集成
b. pytest插件
- pytest
- pytest-html 生成html格式的自动化测试报告
- pytest-xdist 测试用例分布式执行,多CPU分发
- pytest-ordering 用于改变测试用例的执行顺序
- pytest-rerunfailures 用例失败后的重跑
- allure-pytest 用于生成allure的报告
c. pytest插件安装
- 全局安装, 这里以windows为例,首先需要安装好python环境, 然后设置pip为全局环境变量,新建一个requirements.txt,将所有插件按顺序复制到txt文档中,然后打开cmd运行 pip install -r 绝对路径\requirements.txt来安装插件即可
- 虚拟环境安装(具体可以网上搜一下如何创建虚拟环境),然后使用相同的命令安装,这时候这些插件就只能作用于当前工作目录
d. pytest使用规则
- 模块名必须以test_开头或者_test结尾
- 测试类必须以Test开头,并且不能有init方法
- 测试方法必须以test开头
e. pytest测试用例运行模式
- 运行所有 pytest.main()
- 指定模块 pytest.main([‘-vs’, ‘module’]) # 模块为可选,如果没有默认运行当前项目下的所有用例
- 指定目录 pytest.main([‘-vs’, ‘./path’]) # 运行的主脚本需要在整个项目根目录下,然后指定目录
- 通过nodeid指定用例运行: nodeid由模块名,分隔符,类名,方法名,函数名组成
例: pytest -vs ./目录/xx.py ::类名::方法名 # 4方法不常用
示例:
pytest.main() # 运行所有
pytest.main(['-vs', 'test_module']) # 运行指定模块
pytest.main(['./test_path']) # 运行指定目录
- 运行所有 pytest
- 指定模块 pytest -vs xx.py #模块为可选,如果没有默认运行当前项目下
- 指定目录 pytest -vs ./目录 #运行的主脚本需要在整个项目根目录下,然后指定目录
pytest # 运行所有
pytest xx.py # 运行指定模块
pytest './test_path' # 运行指定目录
pytest.ini 是pytest单元测试框架的核心配置文件
1. 位置: 一般存放在项目的根目录
2. 编码:必须是ANSI, 可以用Notepad++修改编码格式
3. 作用:改变pytest默认的行为, 例如文件名可以不以Test_开头,类名,函数名皆可
4. 运行的规则:不管是主函数模式运行,还是命令行运行模式,都会去读取这个配置文件。
5. pytest.ini格式:
[pytest]
addopts = -vs # 命令行参数, 用空格分隔,可选
testpaths = path # 测试用例文件夹,可自己配置,可选
python_files = .py # 配置测试搜索的模块文件名称,可选
python_classes = class_name # 配置测试搜索的测试类名,可选
python_functions = test_ # 配置测试搜索的测试函数名,可选
注: 配置文件中不要保留中文,这里只是注释,编码ANSI会乱码-s: 表示输出调试信息,包括print打印的消息
-v: 显示更详细的信息
-vs: 两个参数可以一起使用
-n process_num: 支持多线程或者分布式运行用例 # 需要插件pytest-xdist
–reruns num:用例失败后重新执行 # 需要插件pytest-rerunfailures
-x:表示只要一个用例报错则测试停止
–maxfail=2: 出现两个用例失败就停止
-k: 根据测试用例的部分字符串指定测试用例
–html xxx.html:生成html的测试报告
f. pytest执行顺序
- pytest 默认执行顺序是自上而下
- 通过装饰器 @pytest.mark.run(order=1)来指定顺序,当有多个装饰器指定顺序一样时,按照自上而下执行,此装饰器需要安装插件pytest-ordering
g. 分组执行 markers
markers是pytest里面用于区分测试用例的标签,主要有两种使用方法
- 命令行模式 pytest -vs -m “标签名”
- pytest.ini文件中增加 markers[标签名: 标签说明]
[pytest]
…… # 前面内容省略
markers:
label1:标签说明
label2:标签说明
示例:
import pytest
class TestCase:
@pytest.mark.label1
xxxx
@pytest.mark.label2
def test_02(self):
xxxx
命令行执行: pytest -vs -m “label” or pytest -vs -m “label1 or label2”
如果使用pytest.ini 则直接pytest -vs即可
h. 跳过测试用例
@pytest.mark.skipif(condition, reason)
示例:
age =18
@pytest.mark.skipif(age >=18, reason ='已成年')
def xxx(self):
xxx
#条件达成True,跳过测试用例,反之false,执行用例
无条件跳过
@pytest.mark.skipif(reason)
@pytest.mark.skipif('理由')
@pytest.mark.skipif(reason ='理由')
两种方式皆可
i. pytest测试夹具(前置后置)
import pytest
class Test:
def setup(self):
print('测试用例执行前执行:打开浏览器')
def test_01(self):
print('测试用例一')
def teardown(self):
print('测试用例执行后执行: 关闭浏览器')
import pytest
class Test:
def setup_class(self):
print('在每个类执行前的初始化操作: 比如创建日志对象,创建数据库链接')
def test_01(self):
print('测试用例一')
def teardown_class(self):
print('在每个类执行后的扫尾操作: 比如销毁日志对象,关闭数据库链接')
@pytest.fixture(scope=”, params=”, ids=”, names=”, autouse=False)
scope
1. function
@pytest.fixture(scope=’function’)# 类似于setup/teardown
import pytest
@pytest.fixture(scope='function')
def my_fixture():
print('这是前后置方法,可以实现部分以及全部用例的前后置')
yield
print('后置测试方法, 用例执行完之后执行')
class Test:
def test_01(self, my_fixture):
print('测试一')
示例
@pytest.fixture(scope=’function’,autouse=True)
下面用例就无需添加my_fixture ,每个用例执行前后都会执行my_fixture函数, autouse= False则不执行
import pytest
@pytest.fixture(scope='function', autouse=True) #类似于setup/teardown
def my_fixture():
print('这是前后置方法,可以实现部分以及全部用例的前后置')
yield
print('后置测试方法, 用例执行完之后执行')
class Test:
def test_01(self):
print('测试一')
结果: 在用例执行前后执行my_fixture函数
2. class
@pytest.fixture(scope=’class’,autouse=True) # 类似于setup_class/teardown_class
scope为class的时候,必须配autouse=True,因为autouse默认是False,不附上则不执行
import pytest
@pytest.fixture(scope='class', autouse=True)
def my_fixture():
print('这是前后置方法,可以实现部分以及全部用例的前后置')
yield #带yield的函数是一个生成器,附上要return生成内容即可
print('后置测试方法, 用例执行完之后执行')
class Test:
def test_01(self):
print('测试一')
class Test1:
def test_02(self):
print('测试二')
结果: 在Test类的前后执行my_fixture函数,如果有多个类,就每个类的前后执行前置后置一次
3. Module
@pytest.fixture(scope=’module’,autouse=True)
scope为module的时候,必须配autouse=True,因为autouse默认是False,不附上则不执行
import pytest
@pytest.fixture(scope='module', autouse=True)
def my_fixture():
print('这是前后置方法,可以实现部分以及全部用例的前后置')
yield #带yield的函数是一个生成器,附上要return生成内容即可
print('后置测试方法, 用例执行完之后执行')
class Test:
def test_01(self):
print('测试一')
class Test1:
def test_02(self):
print('测试二')
结果: 在Test类的前和Test1类后执行my_fixture函数
4. package/session
这两种用的比较少,以后用到再更新
params
参数化, 支持 [1. list[],2. tuple(),3. list_dict[{},{},{}],4. tuple_dict({},{},{}) ]
import pytest
@pytest.fixture(scope='function', params=['年','月','日']) #params是参数名
def my_fixture(request): #request为固定写法
return request.param #param是属性名
class Test:
def test_01(self, my_fixture):
print('测试一')
Print('----------' + str(my_fixture)) #这里需要强制转换成str
import pytest
def my_fixture(request):
print('前置')
yield request.param #return和yield都表示返回的意思,但是return后面不能有代码,但yield可以
print('后置')
ids
使用params参数化时,给每一个值设置一个变量来替换结果中输出的unicode
@pytest.fixture(scope=’function’, params=[‘年’, ‘月’ ,’日’], ids=[‘nian’ ,’yue’ ,’ri’])
name
给表示被@pytest.fixture标记的方法取一个别名
注: 当设置别名后原本的名称就不能再当参数使用了
import pytest
@pytest.fixture(scope='function', name='aaa')
class Test:
def test_01(self, aaa):
print('测试一')
autouse
是否自动执行,默认为False,True则自动执行
不常用的另一种方法
conftest.py和 @pytest.fixture 结合使用全局 的前置 应用
conftest.py文件是单独存放的一个夹具配置文件,名称不能修改
可以在不同的py文件中使用同一个fixture函数
原则上 conftest.py和需要调用的用例在同一层目录,无须import操作
可以每个模块全局,也可以整个项目全局,注意这种使用情况的话,调用顺序为先项目全局再模块全局
- setup/teardown, setup_class/teardown_class 作用于所有用例或者类
- @pytest.fixture() 作用可是是部分也可以全局前后置
- conftest.py和@pytest.fixture结合使用,作用域全局的前后置
j. 断言
assert condition
k. pytest+allure测试报告
验证添加是否成功,打开cmd,运行allure –version,查看是否添加成功
命令行模式 pytest -vs –alluredir ./temp
pytest.ini文件
[pytest]
addopts = -vs –alluredir ./temp
…..allure generate ./temp -o ./report –clean
参数解释
./temp 临时json格式的报告路径
-o 输出output参数
./report 生成allure报告的路径
–clean 清空./report路径原来的报告
l. @pytest.mark.parametrize装饰器
@pytest.mark.parametrize(args_name, args_value),一般有两种用法
args_name: 参数名
args_value: 参数值(list, tuple,list_dict, tuple_dict), 有多个值用例就会执行多次
- 第一种用法
传入一个list,然后查看结果,将整个列表 “年 月 日”打印出来
import pytest
class TestApi:
@pytest.mark.parametrize('args',['年', '月', '日']) # 传入了一个list
def test_01(self, args):
print(args)
if __name__='__main__':
pytest.main()
- 第二种用法
和unittest里面ddt的@unpack解包一致,将两个列表item1,item2依次传入test01用例,结果打印两次分别是”年 月 日”,”小时 分 秒”
import pytest
class TestApi:
@pytest.mark.parametrize('args, item1, item2', [['年', '月', '日'],['小时', '分', '秒']])
def test_01(self, args, item1, item2):
print(args, item1, item2)
if __name__='__main__':
pytest.main()
m. yaml文件–实现接口自动化
yaml是一种数据格式,支持注释,换行, 多行字符串,裸字符串(整形,字符串),需要安装选择PyYAML插件
1. 用于全局的配置文件 ini/yaml
2. 用于写测试用例(接口测试用例)区分大小写
使用缩进表示层级,不能使用tab键缩进,只能用空格(和python一样)
缩进没有数量限制,只要前面是对齐的就行
注释也是#Map对象:
格式:字典键值对
一行写法:
test:{name: ‘名称’, age: ‘年龄’}
多行写法:
test:
name: ‘名称’
age: ‘年龄’数组:
格式:列表字典键值对
一行的写法
–
test: [{name: ‘名称’},{age: ‘年龄’}]
多行写法:
–
test
– name: ‘名称’
– age: ‘年龄’
–
test1:
– name: ‘名称’
– age: ‘年龄’yaml文件就以字典键值对为例
test:{name: ‘名称’, age: ‘年龄’},确保文件和脚本在同一目录,这里python运行即可,不要用pytest
import yaml
class YamlUtil:
def __init__(self, yaml_file):
"""
通过init方法将yaml文件传入这个类
:param yaml_file:
"""
self.yaml_file = yaml_file
def read_yaml(self):
"""
读取yaml, 对yaml反序列化, 就是把yaml格式转换成dict格式
:return:
"""
with open(self.yaml_file, encoding='utf-8') as file_object:
value = yaml.load(file_object, Loader=yaml.FullLoader)
print(value)
if __name__ == '__main__':
YamlUtil('test_api.yaml').read_yaml()
结果: {‘test’: {‘name’: ‘姓名’, ‘age’: ‘年龄’}
Original: https://blog.csdn.net/weixin_41923467/article/details/122449137
Author: LL-Dynabook
Title: [Selenium Web UI自动化测试笔记-pytest]
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/773828/
转载文章受原作者版权保护。转载请注明原作者出处!