apytest是python的一种单元测试框架,与python自带的unittest测试框架类似,但更简洁并高效。特点:
1 安装pytest
pip3 install pytest
2 执行pytest
import pytest
pytest.main([paramas])
paramas可带参数介绍(多参数用 , 分隔)
- -s 显示执行的输出内容
- -v 显示执行的用例信息
- -m 选择执行的标记用例
3 pytest 用例识别机制
- 在运行的项目目录下自动查找 test_开头的或者_test结尾的文件
- 兼容unittest的用例编写方法
- 用例文件中以test_开头的函数会被当成测试用例
- 用例文件中以Test开头的类,里面test_开头的方法,会被当成用例
- 不能在测试类中写init方法
- 可以通过pytest.ini文件去自定义用例识别的机制
3.1 pytest中用例执行的顺序:
- 用例文件名以ascii码进行排序
- 用例文件中的用例:按照用例编写的先后顺序来执行的
3.2 pytest.ini 自定义用例识别:
pytest.ini 可以用来修改pytest识别测试用例的机制 在项目根目录下创建pytest.ini文件[文件名不可自定义]
[pytest]
python_files =
test_*.py
_test*.py
example_*.py
python_functions =
*_test
test_*
python_classes =
Test*
*Test
- python_files 可被识别的python文件名
- python_functions 可被识别的函数名
- python_classes 可被识别的类名
4 pytest 前置后置
4.1 setup/teardown
| 级别 | 写法 |
|---|---|
| 用例级 | setup/teardown |
| 类 | setup_class/teardown_class |
| 模块 | setup/teardown |
def setup():
print("-----模块的前置setup-----")
def teardown():
"""用例基本的前置"""
print("----------模块的后置-----------------")
class TestDome2(object):
def setup(self):
"""用例基本的前置"""
print("----------用例级别的前置-----------------")
def teardown(self):
"""用例基本的前置"""
print("----------用例级别的后置-----------------")
def setup_class(self):
"""用例基本的前置"""
print("----------测试类级别的前置-----------------")
def teardown_class(self):
"""用例基本的前置"""
print("----------测试类级别的后置-----------------")
def test_demo2_method01(self):
print("测试用例:test_demo2_method01")
assert 100 == 100
def test_demo2_method03(self):
print("测试用例:test_demo2_method03")
assert 10 in [10, 22, 33]
4.2 测试夹具 pytest.fixture(*params)
pytest.fixture 测试夹具添加前置后置
4.2.1 pytest.fixture(autouse=) 测试夹具的执行方式
- True 测试夹具自动执行
@pytest.fixture(autouse=True)
def case_setup():
print("---测试用例执行的前置---")
yield # 分割前后置的 yeild之前是前置方法,yeild之后是后置
print("---测试用例执行的后置---")
class TestDemo:
def test_01(self):
print('--case3----99 == 99--------')
assert 99 == 99
def test_02(self, case_setup):
print('--case4----100 == 100--------')
assert 100 == 100
- False 指定具体的测试用例(泛指)填写需要执行的测试夹具
@pytest.fixture()
def case_setup():
print("---测试用例执行的前置---")
token = 'safiudhfoahsof8q294181'
id = 999
yield token, id # 分割前后置的 yeild之前是前置方法,yeild之后是后置
print("---测试用例执行的后置---")
class TestDemo:
@pytest.mark.main
def test_01(self, case_setup): # 执行测试夹具
print('--case1----100 == 100--------')
assert 100 == 100
def test_02(self, case_setup): # 执行测试夹具
print('--case2----99 == 99--------')
assert 100 == 100
def test_03(self): # 不执行测试夹具
print('--case3----99 == 99--------')
assert 99 == 99
def test_04(self, case_setup): # 执行测试夹具
print('--case4----100 == 100--------')
assert 100 == 100
4.2.2 pytest.fixture(scope=) 测试夹具的执行级别
- function 用例级[默认]
- class 类级[同一个类中 类级别的前后置只会执行一次 用例指定时需写在类中第一条用例参数中]
- module 模块级
- package 包级
- session 会话级
@pytest.fixture(scope='module', autouse=True)
def case_setup03():
print("---&&&&&用例模块执行的前置***---")
yield # 分割前后置的 yeild之前是前置方法,yeild之后是后置
print("---&&&&&用例模块执行的后置****---")
@pytest.fixture()
def case_setup():
print("---测试用例执行的前置---")
token = 'safiudhfoahsof8q294181'
id = 999
yield token, id # 分割前后置的 yeild之前是前置方法,yeild之后是后置
print("---测试用例执行的后置---")
@pytest.fixture(scope='class')
def case_setup02():
# 测试类级别的前后置:同一个测试类只会执行一次
print("---***测试类执行的前置***---")
yield # 分割前后置的 yeild之前是前置方法,yeild之后是后置
print("---***测试类执行的后置****---")
class TestDemo:
@pytest.mark.main
def test_01(self, case_setup, case_setup02): # 执行用例级别 和 类级别前后置
res = case_setup
print("前置中返回的数据:", res)
print('--case1----100 == 100--------')
assert 100 == 100
def test_02(self, case_setup):
print('--case2----99 == 99--------')
assert 100 == 100
def test_03(self):
print('--case3----99 == 99--------')
assert 99 == 99
def test_04(self, case_setup):
print('--case4----100 == 100--------')
assert 100 == 100
class TestDemo2:
def test_201(self):
print('--case1----100 == 100--------')
assert 100 == 100
def test_202(self):
print('--case2----99 == 99--------')
assert 100 == 100
def test_203(self):
print('--case3----99 == 99--------')
assert 99 == 99
def test_204(self):
print('--case4----100 == 100--------')
assert 100 == 100
4.2.3 @pytest.mark.usefixtures(*params)
params:为添加的夹具名称 名称要求是字符串 同样可以为添加前后置 但是无法传递前后置内部参数
import pytest
@pytest.fixture()
def case_setup():
print("---测试用例执行的前置---")
token = 'safiudhfoahsof8q294181'
id = 999
yield token, id # 分割前后置的 yeild之前是前置方法,yeild之后是后置
print("---测试用例执行的后置---")
@pytest.fixture(scope='class')
def case_setup02():
# 测试类级别的前后置:同一个测试类只会执行一次
print("---***测试类执行的前置***---")
yield # 分割前后置的 yeild之前是前置方法,yeild之后是后置
print("---***测试类执行的后置****---")
@pytest.mark.usefixtures("case_setup", 'case_setup02') # 添加类级别和用例级别前后置
class TestDemo2:
pytestmark = [pytest.mark.main, ]
def test_201(sel):
print('--case1----100 == 100--------')
assert 100 == 100
def test_202(self):
print('--case2----99 == 99--------')
assert 100 == 100
def test_203(self):
print('--case3----99 == 99--------')
assert 99 == 99
def test_204(self):
print('--case4----100 == 100--------')
assert 100 == 100
4.3 前后置传递参数(yield)
- 测试夹具内的 yield 后 跟需要返回的参数 然后在测试用例中接收
@pytest.fixture()
def case_setup():
print("---测试用例执行的前置---")
token = 'safiudhfoahsof8q294181'
id = 999
yield token, id # 分割前后置的 yeild之前是前置方法,yeild之后是后置
print("---测试用例执行的后置---")
class TestDemo:
def test_01(self, case_setup):
res = case_setup # 接收 case_setup 中返回的参数
print("前置中返回的数据:", res)
print('--case1----100 == 100--------')
assert 100 == 100
- 向测试夹具内的传递参数 在测试夹具内调用内部函数,向函数传递参数
@pytest.fixture()
def login_setup():
'''登录测试用例前后置'''
def _login_setup(loginpage):
loginpage.fresh()
yield _login_setup # 分割前后置的 yeild之前是前置方法,yeild之后是后置
class Test_login():
'''
description: 网页登录用例类
param :
return {type}
'''
test_data = yaml.load(open(testpath.TestData, encoding="utf-8"), Loader=yaml.FullLoader)["test_data"]
@pytest.mark.parametrize('kwargs', test_data)
def test_login(self, kwargs, login_setup_class, login_setup):
self.loginpage = login_setup_class
login_setup(self.loginpage)
self.loginpage.login(kwargs['phone'], kwargs['pwd'])
res_ele = self.loginpage.find_ele(pat=kwargs['xpath'],pat_params=kwargs['expected'])
assert res_ele
4.4 测试夹具统一管理文件(conftest)
conftest.py 文件内统一存放测试用例的前后置 pytest可以自动去查找而无需进行导包[文件名不可修改]
5 标记
标记可以在执行测试过程中有选择的执行部分用例.标记分自带标记和自定义标记两种
5.1 自定义标记
- 注册标记 在pytest.ini文件中写入标记名称(marks = "标记" 必须用双影号)
[pytest]
markers =
mains
musen
demo5
- 给用例打标记(@pytest.mark.main)
import pytest
@pytest.mark.next
@pytest.mark.usefixtures("case_setup", 'case_setup02')
class TestDemo3:
@pytest.mark.main
def test_301(sel):
print('--case1----100 == 100--------')
assert 100 == 100
def test_302(self):
print('--case2----99 == 99--------')
assert 100 == 100
def test_303(self):
print('--case3----99 == 99--------')
assert 99 == 99
def test_304(self):
print('--case4----100 == 100--------')
assert 100 == 100
或者
import pytest
@pytest.mark.usefixtures("case_setup", 'case_setup02')
class TestDemo3:
pytestmark = [pytest.mark.标记名] # 类标记
def test_301(sel):
print('--case1----100 == 100--------')
assert 100 == 100
def test_302(self):
print('--case2----99 == 99--------')
assert 100 == 100
def test_303(self):
print('--case3----99 == 99--------')
assert 99 == 99
def test_304(self):
print('--case4----100 == 100--------')
assert 100 == 100
- 执行标记用例
pytest.main(["-m","标记名"] # 符合单一标记
pytest.main(["-m","标记名 and 标记名"] # 符合多个标记名用例
pytest.main(["-m","标记名 or 标记名"] # 符合任一标记名用例
- 执行指定路径用例
pytest.main(["-m","文件路径::模块::类::用例名"] # 符合任一标记名用例
6 参数化标记
运用原理类似ddt @pytest.mark.parametrize('接受的变量名', 数据变量名)
import pytest
cases = [
100,
101,
102,
103,
]
@pytest.mark.demo5
class TestDemo4:
@pytest.mark.parametrize('item', cases)
def test_login(self, item):
assert 100 == item
7 重运行失败用例
- 安装插件
pip3 install pytest-rerunfailures
- 执行命令
pytest --reruns 3 --reruns-delay 5 # 3表示运行次数 5表示运行间隔时间(s)
命令行执行pytest 需要在用例文件夹下添加__init__.py文件
8 测试报告
8.1 pytest-html
安装:pip3 install pytest-html
终端输入:pytest --html=report.html
8.2 allure
8.2.1 安装allure
下载离线版allure后 将bin目录地址添加到系统环境变量中 后cmd中确认
8.2.2 安装allure-pytest
pip3 install allure-pytest
8.2.3 allure报告生成地址
--alluredir=result/report[相对于启动文件的路径地址]"
8.2.4 启动allure
- 通过命令启动
allure serve result/report[报告路径地址]
- 通过代码启动
import os
os.system('allure serve result/report[报告路径地址]')
8.2.5 jenkins集成allure
- 安装allure插件
- 配置allure插件
- jenkins发送allure报告
<h1><center><font>以下是Jenkins自动发送的邮件,请勿回复!</font><center></h1>
<h3><center><font color="red">allure报告在线查看or下载allure-report.zip用firefox离线查看,测试用例见附件</font><center></h3>
<br>
<hr>
<br>
项目描述:${JOB_DESCRIPTION}<br>
<br>
<hr>
项目名称:$PROJECT_NAME<br>
构建编号:$BUILD_NUMBER<br>
构建状态:$BUILD_STATUS<br>
触发原因:${CAUSE}<br>
构建地址:<A HREF="${BUILD_URL}">${BUILD_URL}</A><br>
构建日志地址:<A HREF="${BUILD_URL}console">${BUILD_URL}console</A><br>
系统allure测试报告:<A HREF="${PROJECT_URL}${BUILD_NUMBER}/allure">${PROJECT_URL}${BUILD_NUMBER}/allure</a><br>
<hr>
${JELLY_SCRIPT}
然后点击应用点击保存就可以了
9 服务器运行web自动化
9.1 服务器安装项目所运行的python环境
- 安装python版本
- 安装项目运行的依赖包
导出项目第三方库
pip freeze > 第三方库文件的路径
导入项目第三方库pip install -r 第三方库文件的路径
9.2 服务器安装浏览器和驱动
- 浏览器的启动参数(以chrome为例)
https://www.cnblogs.com/softSupermaket/p/13474203.html[转载]
9.3 以无头模式启动浏览器(以chrome为例)
from selenium import webdriver
options = webdriver.ChromeOptions()
# 无头模式
options.add_argument('--headless')
# 禁用GPU
options.add_argument('--disable-gpu')
# 非沙箱环境
options.add_argument('--no-sandbox')
driver = webdriver.Chrome(options=options)