1.pytest框架
1.1.引入
常用单元测试框架介绍
python:pytest,unittest
java:TestNG,Junit
pytest主要作用:
- 找到测试用例
- 执行测试用例
- 判断测试结果
- 生成测试报告
pytest默认的测试用例规则(可在pytest.ini中修改规则):
- 模块名必须以test_开头或_test结尾
- 测试类必须以Test开头,并且不能有init方法
- 测试用例必须以test开头
1.2 安装相关插件
pytest常用插件:
- pytest-html(生成html报告)
- pytest-xdist(多线程运行)
- pytest_ordering(控制用例的执行顺序)
- pytest-rerunfailure(失败用例重跑)
- allure-pytest(生成allure报告)
- pytest-base-url(管理基础路径)
- pytest(自身)
安装插件
1.新建项目
2.项目根路径新建 requirements.txt
3.在requirements.txt文件录入需要的插件:
pytest-html
pytest-xdist
pytest_ordering
pytest-rerunfailures
allure-pytest
pytest-base-url
pytest
pyyaml
rsa
4.安装插件:终端窗口输入命令:pip install -r requirements.txt
1.3 pytest.ini配置文件
1.3.1 引入
执行测试用例的三种方式
- 命令行执行:pytest
- 主函数执行(项目根路径下新建run.py文件)录入:
import pytest if __name__=='__main__': pytest.main()
3. 通过pytest.ini全局配置文件执行
项目根目录下新建pytest.ini,录入:
[pytest]
#命令行参数,多个参数之间用空格分割
addopts= -vs -n=2 --reruns=2 --maxfail=3 -m "smoke or user" --alluredir=./temps --clean-alluredir
#指定测试用例的文件夹
testpaths=./testcases
#修改默认的模块规则
python_files=test_*.py
#修改默认的类的规则
python_classes=Test*
#修改默认的测试用例规则
python_functions=test_*
#用例标记
markers=
smoke:冒烟用例
user:用户管理
输入命令参数需要:
- 不要复制粘贴,请手动写
- 每个命令之间只有一个空格,不要弄多个空格
- 不要在中文环境下手写
注意:如果写入了中文,就需要吧pytest.ini文件改成GBK编码格式
1.3.2 pytest参数解释:
- -vs:输出详细信息和调试信息
- -n=2:多线程
- --reruns=2:失败用例重跑
- -x:失败一次就中止用例的执行
- --maxfail=3:失败3次就中止用例的执行
- --html=./report/report.xml:生成html报告
- -m "smoke or user" 执行指定标记的用例
- --alluredir=./temps allure临时报告路径
- --clean-alluredir 每次生成时清空上次的临时报告数据
1.4 pytest使用
1.4.1 指定标记的用例
class Testuser: @pytest.mark.user def test_add_user(self): print("添加用户成功") pass @pytest.mark.smoke def test_query_user(self): print("查询用户成功")
1.4.2 pytest跳过用例
无条件跳过:@pytest.mark.skip(reason="原因")
class Testuser: @pytest.mark.user @pytest.mark.skip(reason="删除用户功能暂不执行") def test_delete_user(self): pass
有条件跳过:@pytest.mark.skipif(a<10,reason="原因")
class TestLogin: a=8 @pytest.mark.skipif(a<10,reason="跳过") def test_login_fail_username_isnull(self): pass
1.4.3 pytest控制执行顺序
默认是按照文件夹名,py文件名,测试用例名从上到下的顺序执行的
通过pytest-ordering模块来改变执行顺序
class TestLogin: @pytest.mark.smoke @pytest.mark.run(order=1) def test_login_sucess(self,init_sql,base_url): url="user/login" new_url=base_url+url print("登录成功"+init_sql)
1.4.4 pytest前置和后置操作
在用例之前和用例之后需要执行的内容
不能更改的前后置操作
class TestLogin: a=8 def setup_class(self): print("在类之前执行") def teardown_class(self): print("在类之后执行") def setup(self): print("在每个用例之前执行setup") def teardown(self): print("在每个用例之后执行") @pytest.mark.smoke @pytest.mark.run(order=1) def test_login_sucess(self,init_sql,base_url): url="user/login" new_url=base_url+url print("登录成功"+init_sql)
可灵活更改的前后置操作@pytest.fixture()
fixture的语法:
@pytest.fixture(scope="作用域",autouse="自动使用",params="参数化",ids="参数别名",name="固件别名")
模块内置:
1.scope=function的场景
@pytest.fixture(scope="function",autouse=False) def init_sql(): print("执行sql,初始化数据") yield print("关闭数据库链接") class TestLogin: @pytest.mark.smoke @pytest.mark.run(order=1) def test_login_sucess(self,init_sql): print("登录成功"+init_sql) @pytest.mark.smoke def test_login_fail_password_error(self): print("密码错误,登录失败") @pytest.mark.smoke def test_login_fail_password_isnull(self,init_sql): print("密码为空,登录失败")
2.scope=class的场景
@pytest.fixture(scope="class",autouse=False) def init_sql(): print("执行sql,初始化数据") yield print("关闭数据库链接") @pytest.mark.usefixtures("init_sql") class TestLogin: @pytest.mark.smoke @pytest.mark.run(order=1) def test_login_sucess(self): print("登录成功") @pytest.mark.skipif(a<10,reason="跳过") def test_login_fail_username_isnull(self): pass @pytest.mark.smoke def test_login_fail_password_error(self): print("密码错误,登录失败")
3.scope=module的场景很少使用
@pytest。fixture(scope="module",autouse=Ture)
一般只有自动,如果一个模块中只有一个类,那么module和类的效果差不多
@pytest.fixture(scope="module",autouse=True) def init_sql(): print("执行sql,初始化数据") yield print("关闭数据库链接")
class TestLogin: @pytest.mark.smoke @pytest.mark.run(order=1) def test_login_sucess(self): print("登录成功") @pytest.mark.skipif(a<10,reason="跳过") def test_login_fail_username_isnull(self): pass @pytest.mark.smoke def test_login_fail_password_error(self): print("密码错误,登录失败")
4.scope=package/session的场景(一般只有自动,整个会话)
@pytest.fixture(scope="session",autouse=True) def init_sql(): print("执行sql,初始化数据") yield print("关闭数据库链接") class TestLogin: @pytest.mark.smoke @pytest.mark.run(order=1) def test_login_sucess(self): print("登录成功") @pytest.mark.skipif(a<10,reason="跳过") def test_login_fail_username_isnull(self): pass
5.params参数化,数据是list格式或者是list of dict格式
import pytest @pytest.fixture(scope="function" autouse=False,params=[{"name":"张三"},{"name":"李四"}],name="sql") def exe_sql(request): print("aaa") yield request.param print("aaaa") @pytest.mark.usefixtures("init_sql") class TestLogin: @pytest.mark.smoke @pytest.mark.run(order=1) def test_login_sucess(self,exe_sql): print(exe_sql) print("登录成功")
ids参数化之后对参数的别名,必须和params一起使用
name是固件的别名,特别注意:一旦固件加了别名之后,name就只能使用别名
conftest.py文件
是专门用来存放fixture固件的py文件,名字是固定的
不需要做任何的导包,不管是在根目录,还是在用例目录,还是在模块目录,都会被自动的发现并执行
执行顺序,从最外面往内层执行,如果是同一个conftestname按照固件名的ASCII码先后执行
#conftest.py import pytest @pytest.fixture(scope="function" autouse=False,params=[{"name":"张三"},{"name":"李四"}],name="sql") def exe_sql(request): print("aaa") yield request.param print("aaaa")
前后置操作优先级:
先执行根目录下的conftest.py里面的fixture的类级别
读取pytest.ini配置,找到测试用例
执行测试用例目录下的conftest.py文件中的fixture的类级别
执行测试用例模块目录下的conftest.py文件中的fixture的类级别
setup_class
然后按根目录。测试用例目录,测试用例下的模块目录的函数级别fixture
setup
执行测试用例
然后从里到外依次执行后置
执行结果:
testcases/a/test_login.py::TestLogin::test_login_success c1 c2 c3 在类之前执行 func1 func2 func3 在用例之前执行 测试登录用例执行 PASSED在测试用例之后执行 func3 func2 func1 在类之后执行 c3 c2 c1
执行结果说明:
- 其中c1,c2,c3是conftest.py文件中类级别的fixture
- func1,func2,func3是conftest.py文件中function级别的fixtre
- c1和func1是根目录下的conftest.py文件
- c2和func2是用例目录testcases下的conftest.py文件
- c3和func3是用例模块目录a下的conftest.py文件
- 在类之前执行是用例模块下setup_class函数
- 在用例之前执行是用例模块下setup函数
- 在测试用例之后执行是用例模块下teardown函数
- 在类之后执行是用例模块下teardown_class函数
1.4.5 环境变量
(基础路径):开发,测试,预发布,线上
base_ur就是基于function级别的手动调用的fixture
#pytest.ini文件 [pytest] #命令行参数,多个参数之间用空格分割 addopts= -vs --reruns=2 -m "smoke or user" #指定测试用例的文件夹 testpaths=./testcases #修改默认的模块规则 python_files=test_*.py #修改默认的类的规则 python_classes=Test* #修改默认的测试用例规则 python_functions=test_* #环境变量 base_url="http://dev.ceshi.com" #用例标记 markers= smoke:冒烟用例 user:用户管理
路径使用
class TestLogin: @pytest.mark.smoke @pytest.mark.run(order=1) def test_login_sucess(self,init_sql,base_url): url="user/login" new_url=base_url+url print("登录成功"+init_sql)
1.4.6 断言
使用pyton的断言
assert "http" in url
assert 1==2
class TestLogin: @pytest.mark.smoke @pytest.mark.run(order=1) def test_login_sucess(self,init_sql,base_url): url="user/login" new_url=base_url+url assert "http" in new_url assert 3==4 print("登录成功"+init_sql)
1.4.7 allure报告
1.4.7.1 安装allure和插件
1.先安装插件allure-pytest
2.官网下载allure的包,解压到没有中文的路径:https://github.com/allure-framework/allure2/releases
3.检查各软件是否匹配:
- python版本:3.10.X
- allure 2.13+
- allure-pytest:2.10
- pytest:7.1+
4.配置allure的环境变量,把D:\allure-2.18.1\bin配置到path路径
5.验证是否安装完成,需腰验证两次
- 在命令提示符窗口,输入:allure --version
- pychram窗口,输入:allure --version
1.4.7.2 生成报告
1.pytest.ini中配置临时报告路径,以及每次清除临时报告数据
[pytest] #命令行参数,多个参数之间用空格分割 addopts= -vs --reruns=2 -m "smoke or user" --alluredir=./temps --clean-alluredir #指定测试用例的文件夹 testpaths=./testcases #修改默认的模块规则 python_files=test_*.py #修改默认的类的规则 python_classes=Test* #修改默认的测试用例规则 python_functions=test_* #环境变量 base_url="http://dev.ceshi.com" #用例标记 markers= smoke:冒烟用例 user:用户管理
2.run.py文件里面:
# run.py import os import time import pytest if __name__=='__main__': pytest.main() time.sleep(3) os.system("allure generate ./temps -o ./reports --clean")
保存历史报告:
#run.py import os import time import pytest if __name__=='__main__': pytest.main() files_name="./reports/report_"+str(int(time.time())) os.mkdir(files_name) time.sleep(3) os.system("allure generate ./temps -o "+files_name+" --clean")
1.4.8 企业级allure报告定制
1.4.8.1 企业logo定制
1.修改D:\allure-2.18.1\config目录下的allure.yaml文件,增加自定义logo插件
#allure.yaml plugins: - junit-xml-plugin - xunit-xml-plugin - trx-plugin - behaviors-plugin - packages-plugin - screen-diff-plugin - xctest-plugin - jira-plugin - xray-plugin - custom-logo-plugin
2.更改custom-logo-plugin目录下的logo图片以及样式style.css
2.1 修改图片名称(如231.png)
2..2修改style.css
.side-nav__brand { background: url('231.png') no-repeat left center !important; margin-left: 10px; height:90px; background-size contain !important; } .side-nav__brand-text{ display:none; }
1.4.8.2 allure报告左边定制
@allure.epic("项目名称:易宝商城接口自动化测试")
@allure.feature("模块名称:商品管理模块测试用例")
@allure.story("接口名称:商品列表接口")
@allure.title("用例名称:查询商品成功")
import allure import pytest @allure.epic("项目名称:易宝商城接口自动化测试") @allure.feature("模块名称:商品管理模块测试用例") class TestProduct: @pytest.mark.smoke @allure.story("接口名称:商品列表接口") @allure.title("用例名称:查询商品成功") def test_get_productlist(self): print("商品列表展示成功")
1.4.8.3 allure报告右边定制
@allure.severity(allure.severity_level.BLOCKER) #优先级(严重级别)
1.优先级:
致命(blocker),严重(critical),一般(normal),提示(minor),轻微(trivial)
@allure.description("用例描述:输入商品名正确,查询商品成功")
with allure.step(f"第{a}步:接口执行步骤如下:"):
allure.attach()#附件
import allure import pytest @allure.epic("项目名称:易宝商城接口自动化测试") @allure.feature("模块名称:商品管理模块测试用例") class TestProduct: @pytest.mark.smoke @allure.story("接口名称:商品列表接口") @allure.title("用例名称:查询商品成功") @allure.description("用例描述:输入商品名正确,查询商品成功") @allure.severity(allure.severity_level.BLOCKER) #优先级(严重级别) @allure.link("访问接口的链接") #访问接口的链接 @allure.issue("bug链接") #bug链接 @allure.testcase("测试用例的链接") #测试用例的链接 def test_get_productlist(self): print("商品列表展示成功") for a in range(1,11): with allure.step(f"第{a}步:接口执行步骤如下:"): print(f"执行第{a}步") #增加附件 with open("D:\\231.png",mode='rb') as f: content=f.read() allure.attach(body=content,name="错误截图", attachment_type=allure.attachment_type.PNG) #加文本 allure.attach("http://www.yibao.com","接口地址",allure.attachment_type.TEXT) allure.attach("Get","接口请求方式",allure.attachment_type.TEXT)
使用allure报告脱离pycharm访问:
局域网:allure open ./reports
标签:allure,框架,test,mark,用例,pytest,使用,print From: https://www.cnblogs.com/lgs-tech/p/17465846.html