pytest从入门到精通-1
pytest从入门到精通-1 一、pytest单元测试框架 二、单元测试框架和自动化测试框架有什么关系 三、pytest简介 1.什么是单元测试框架 单元测试是指在软件开发当中,针对软件的最小单位(函数,方法)进行正确性的检查 测试 2.单元测框架的分类 3.单元测试框架主要做什么 java junit testng python unittest pytest 1.测试发现 2.测试执行 3.测试判断 4.测试报告 从多个文件里面去找测试用例 按照一定的顺序和规则去执行,并生成结果 通过断言判断预期结果和实际结果的差异 统计测试进度,耗时,通过率等,生成测试报告 1.什么是自动化测试框架 2.自动化测试框架的作用 自动化测试框架是由测试组长或者自动化测试主管搭建的一套用于自动化测试的系统框 1.提高测试效率,降低维护成本 2.减少人工干预,提高测试的准确性,增加代码的重用性 3.核心思想是让不懂代码的人也能够通过这个框架去实现自动化测试 3.pytest单元测试框架和自动化测试框架的关系 单元测试框架是自动化测试框架中的组成部分之一 pom设置模式是自动化测试框架中组成部分之一 数据驱动是自动化测试框架中组成部分之一 关键字驱动是自动化测试框架中组成部分之一 全局配置文件是自动化测试框架中组成部分之一 日志监控是自动化测试框架中组成部分之一 pytest全局配置文件为pytest.ini, 需要放置在项目的根目录下 selenium,requests二次封装是自动化测试框架中组成部分之一 断言是自动化测试框架中组成部分之一 报告邮件是自动化测试框架中组成部分之一 其他更多的内容 1.pytest是一个非常成熟的python的单元测试框架,比unittest更灵活,更容易上手 2.pytest可以和selenium,requests,appium结合实现web自动化,接口自动化,app自动化 3.pytest可以实现测试用例的跳过以及reruns失败用例重试 4.pytest可以和allure生成非常美观的测试报告 5.pytest可以和Jenkins持续集成 6.pytest有很多非常强大的插件,并且这些插件能够实现很多的实用的操作 插件 pytest pytest-xdist pytest-ordering pytest-rerunfailures pytest-html 用于测试用例分布式执行,多CPU分发 用于改变测试用例的执行顺序 用例失败后重跑 生成html格式的自动化测试报告 allure-pytest 用于生成美观的测试报告 插件安装 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt requirements.txt pytest pytest-xdist pytest-ordering pytest-rerunfailures pytest-html allure-pytest 查看检验安装后的版本 pytest --version 四、使用pytest,默认的测试用例的规则以及基础应用 1.模块名必须以test_开头或者_test结尾 test_baidu.py google_test.py 2.测试类必须以Test开头,并且不能有init方法 class TestBaiDu(): 3.测试方法必须以test开头 def test001(self): print("测试百度搜索") def test002(): print("测试百度登录") class TestBaiDu(): def test001(self): print("测试百度搜索") 五、pytest测试用例的运行方式 1.主函数模式 2.命令模式 参数详解 1.运行所有 pytest.main() import pytest def test002(): print("测试百度登录") class TestBaiDu(): def test001(self): print("测试百度搜索") if __name__ == '__main__': pytest.main() 模块内运行 模块外运行 test_baidu.py import pytest def test002(): print("测试百度登录") class TestBaiDu(): def test001(self): print("测试百度搜索") runPytest.py import pytest pytest.main() test_baidu.py 2.指定模块 3.指定目录 4.通过nodeid指定用例运行 1.运行所有 pytest (mypytest) D:\PycharmProjects\mypytest>pytest pytest.main(['-vs','test_baidu.py']) runPytest.py import pytest pytest.main(['-vs','test_baidu.py']) 2.指定模块 pytest -vs test_baidu.py (mypytest) D:\PycharmProjects\mypytest>pytest -vs test_baidu.py pytest.main(['-vs','./testcase']) runPytest.py import pytest pytest.main(['-vs','./testcase']) 3.指定目录 pytest -vs ./testcase (mypytest) D:\PycharmProjects\mypytest>pytest -vs ./testcase nodeid由模块名,分隔符,类名,方法名,函数名组成 运行目录下模块中的函数 pytest.main(['-vs','./testcase/souhu_test.py::testsouhulogin']) runPytest.py import pytest pytest.main(['-vs','./testcase/souhu_test.py::testsouhulogin']) 其中模块名字和函数之间的分隔符用英文双冒号(::) 运行目录下模块中类的函数 pytest.main(['-vs','./testcase/souhu_test.py::TestSouHu::testsearch']) runPytest.py import pytest pytest.main(['-vs','./testcase/souhu_test.py::TestSouHu::testsearch']) 其中模块名字和类名之间的分隔符用英文双冒号(::) 类名与函数名之间的分隔符也用英文双冒号(::) 4.通过nodeid指定用例运行 pytest -vs ./testcase/souhu_test.py::TestSouHu::testsearch (mypytest) D:\PycharmProjects\mypytest>pytest -vs ./testcase/souhu_test.py::TestSouHu::testsearch 3.通过读取pytest.ini全局配置文件运行 -s 表示输出调试信息,包括print打印的信息 -v 表示更详细的信息,会打印出用例名字和执行结果 -vs 这两个参数一起用 -n 支持多线程或者分布式运行测试用例 主函数模式运行 命令模式运行 runPytest.py import pytest pytest.main(['-vs','./testcase','-n 2']) (mypytest) D:\PycharmProjects\mypytest>pytest -vs ./testcase -n 2 --reruns NUM 失败用例重跑 命令模式运行 (mypytest) D:\PycharmProjects\mypytest>pytest -vs ./testcase -n 2 --reruns 2 -x 表示只要有一个用例报错,那么测试停止 主函数模式运行 命令模式运行 runPytest.py import pytest pytest.main(['-vsx','./testcase']) (mypytest) D:\PycharmProjects\mypytest>pytest -vsx ./testcase --maxfail=2 出现两个用例失败就停止 命令模式运行 (mypytest) D:\PycharmProjects\mypytest>pytest -vs ./testcase --maxfail=2 -k 根据测试用例的部分字符串指定测试用例 命令模式运行 (mypytest) D:\PycharmProjects\mypytest>pytest -vs ./testcase -k "ch" --html ./report/report.html 生成html的测试报告 命令模式运行 (mypytest) D:\PycharmProjects\mypytest>pytest -vs ./testcase -m "smoke or usermanage or productnamage" pytest.ini 这个文件是pytest单元测试框架的核心配置文件 1.位置 2.编码 3.作用 4.运行的规则;不管是主函数的模式运行,命令行模式运行,都会去读这个配置文件。 一般放在项目的根目录 必须是ANSI,可以使用notpad++修改编码格式 改变pytest默认的行为 pytest.ini内容 [pytest] addopts=-vs #命令行的参数,用空格分隔 testpaths=./testcase #测试用例的路径 python_files=test_*.py #模块名的规则 python_classes=Test* #类名的规则 python_functions=test #方法名的规则 使用命令模式运行 (mypytest) D:\PycharmProjects\mypytest>pytest 注释实际配置中要将中文去掉,文件编码模式修改为ANIS编码(用nodepad++修改) [pytest] addopts=-vs --html ./report/report.html testpaths=./testcase python_files=*_test.py python_classes=Test* python_functions=test 六、pytest执行测试用例的顺序是怎样的呢 unittest 是根据测试用例名称的ascII值的大小来绝对的执行的顺序 pytest 默认从上到下顺序执行 改变默认的执行顺序 使用mark标记 @pytest.mark.run(order=1) import pytest def testsouhulogin(): print("登录搜狐") class TestSouHu(): @pytest.mark.run(order=2) def testsearch(self): print("搜狐搜索视频") assert False @pytest.mark.run(order=3) def testclick(self): print("搜狐点击") assert False @pytest.mark.run(order=1) def testswipe(self): print("搜狐滑动") assert False 七、如何分组执行(冒烟,分模块执行,分接口和web执行) smoke 冒烟用例,分布在各个模块里面 -m "smoke or usermanage or productnamage" 分组执行 (mypytest) D:\PycharmProjects\mypytest>pytest -m "smoke" 代码中的标记 import pytest def testsouhulogin(): print("登录搜狐") class TestSouHu(): @pytest.mark.run(order=2) def testsearch(self): print("搜狐搜索视频") assert False @pytest.mark.run(order=3) @pytest.mark.smoke def testclick(self): print("搜狐点击") assert False @pytest.mark.run(order=1) def testswipe(self): print("搜狐滑动") assert False 命令模式运行 (mypytest) D:\PycharmProjects\mypytest>pytest -m "smoke" 代码中标记的“smoke”与命令模式中-m后面的“smoke”一定要一致 八、pytest跳过测试用例 1.无条件跳过 2.有条件跳过 @pytest.mark.skip(reason="太难了") import pytest def testsouhulogin(): print("登录搜狐") class TestSouHu(): @pytest.mark.run(order=2) def testsearch(self): print("搜狐搜索视频") assert False @pytest.mark.run(order=3) @pytest.mark.smoke @pytest.mark.skip(reason="太难了") def testclick(self): print("搜狐点击") assert False @pytest.mark.run(order=1) def testswipe(self): print("搜狐滑动") assert False @pytest.mark.skipif(age>=18,reason='已成年') 第一个参数是条件:age>=18 第二个参数是描述原因:reason='已成年' import pytest def testsouhulogin(): print("登录搜狐") class TestSouHu(): age=18 @pytest.mark.run(order=2) def testsearch(self): print("搜狐搜索视频") assert False @pytest.mark.run(order=3) @pytest.mark.smoke @pytest.mark.skip(reason="太难了") def testclick(self): print("搜狐点击") assert False @pytest.mark.run(order=1) @pytest.mark.skipif(age>=18,reason='已成年') def testswipe(self): print("搜狐滑动") assert False allure 安装allure 1.下载allure 网址::https://github.com/allure-framework/allure2/releases/tag/2.17.3 下载其中的如allure-2.17.3.zip,解压放到本地,并配置环境变量到path,如D:\Program Files\allure-2.17.3\bin(配置到bin目录) 2.验证allure是否配置成功 cmd中或者pycharm的命令行中输入 allure --version 出现版本信息即可 3.生成allure报告 1.先生成临时的json格式的报告 2.再根据生成的json格式的报告生成html的报告 在pytest.ini配置文件中添加 --alluredir ./temps --clean-alluredir [pytest] addopts=-vs --html ./report/report.html --alluredir ./temps --clean-alluredir testpaths=./testcase python_files=*_test.py python_classes=Test* python_functions=test 表示生成临时的json格式的报告到项目根目录下的temps文件夹下; --clean-alluredir,表示先清除temps文件夹下之前的内容,保证是最新的json内容; os.system("allure generate ./temps -o ./reports --clean") 主函数模式运行 runPytest.py import pytest import os import time pytest.main() time.sleep(2) #生成json格式报告后等2秒 os.system("allure generate ./temps -o ./reports --clean") 表示生成的json格式放在temps目录下,生成的报告放在reports目录下; --clean,表示生成报告前先清除原有内容 参数都可以放到pytest.ini中的addopts 的值中 [pytest] addopts=-vs -m "smoke" #命令行的参数,用空格分隔 testpaths=./testcase #测试用例的路径 python_files=test_*.py #模块名的规则 python_classes=Test* #类名的规则 python_functions=test #方法名的规则 [pytest] addopts=-vs -m "smoke" --maxfail=2 --html ./report/report.html #命令行的参数,用空格分隔 4.通过装饰器对allure报告进行定制 1.安装allure-pytest pip install allure-pytest -i https://pypi.tuna.tsinghua.edu.cn/simple 2.查看是否安装allure-pytest pip show allure-pytest 3.使用装饰器对测试报告中的测试用例进行分组 代码 souhu_test.py 说明 @allure.feature 一个大需求 @allure.story 大需求下的一个故事,一个场景 @allure.title 本条用例的标题 4.功能用例和自动化用例做关联 自动化作到什么程度 自动化覆盖率为多少 自动化用例与功能用例无关,则无效 自动化测试用例去覆盖功能用例 一个功能用例 用例标题 前置条件 执行步骤 预期结果 一条自动化测试用例与功能用例的关联 feature 对应的模块 story 对应的场景 用例对应的禅道系统的bug用例url地址,关联起来 issue 如果这个用例有bug,应该关联对应的bug地址 自动化测试用例代码 test_case_01.py """ feature 对应的模块名称 story 对应的场景 用例对应的禅道系统的bug用例url地址,关联起来 issue 如果这个用例有bug,应该关联对应的bug地址 """ import pytest import allure import os import time @allure.feature("编辑分类文章") class TestArticle(): """ 编辑文章分类 """ @allure.story("登录-编辑文章分类,重复保存,保存失败") @allure.issue(url="http://127.0.0.1:8080/zentao/bug-view-1.html",name="不应该重复保存,而实际可以") #关联禅道bug @allure.testcase(url="http://127.0.0.1:8080/zentao/testcase-view-1.html",name="重复保存失败") #关联禅道用例 def test_edit_class(self): """ 用例描述:编辑文章分类-输入重复的分类,保存失败,不能添加重复的 setup(前置条件):登录成功 step(步骤)1:编辑文章分类,输入文章类别,如:计算机 step(步骤)2:点击保存按钮 step(步骤)3:重新打开编辑页面,输入:计算机 step(步骤)4:再次打开保存按钮 assert(断言,验证):保存失败,提示:已存在 """ #用with来做步骤执行,用assert来断言的是否登录成功(如存在某个元素等) with allure.step("setup:登录成功"): print("判断是否登录成功") assert 1==1 #用with来做步骤执行,用assert来断言的是否登录成功(如存在某个元素等) with allure.step("step(步骤)1:编辑文章分类,输入文章类别,如:计算机"): print("step(步骤)1:编辑文章分类,输入文章类别,如:计算机") assert 1==1 #用with来做步骤执行,用assert来断言的是否登录成功(如存在某个元素等) with allure.step("step(步骤)2:点击保存按钮"): print("step(步骤)2:点击保存按钮") assert 1==1 #用with来做步骤执行,用assert来断言的是否登录成功(如存在某个元素等) with allure.step("step(步骤)3:重新打开编辑页面,输入:计算机"): print("step(步骤)3:重新打开编辑页面,输入:计算机") assert 1==1 #用with来做步骤执行,用assert来断言的是否登录成功(如存在某个元素等) with allure.step("step(步骤)4:再次打开保存按钮"): print("step(步骤)4:再次打开保存按钮") assert 1==1 #用with来做步骤执行,用assert来断言的是否登录成功(如存在某个元素等) with allure.step("assert(断言,验证):保存失败,提示:已存在"): print("assert(断言,验证):保存失败,提示:已存在") assert 1==2 if __name__ == '__main__': pytest.main(["-vs","test_case_01.py",'--alluredir','./temps']) time.sleep(2) # 生成json格式报告后等2秒 os.system("allure generate ./temps -o ./reports --clean") # 表示生成的json格式放在temps目录下,生成的报告放在reports目录下, --clean,表示生成报告前先清除原有内容 说明 @allure.feature 模块 @allure.story @allure.issue @allure.testcase 故事,场景 bug关联 用例关联 with allure.step 用例步骤 5.用例的等级 allure 对用例的等级划分成五个等级 blocker critical normal minor trivial 阻塞缺陷(功能未实现,无法下一步) 严重缺陷(功能点缺失) 一般缺陷(边界情况,格式错误) 次要缺陷(界面错误与ui需求不符) 轻微缺陷(必须项无提示,或者提示不规范) 代码 test_case_02.py import pytest import allure import os import time """ 用例等级 allure 对用例的等级划分成五个等级 blocker 阻塞缺陷(功能未实现,无法下一步) critical 严重缺陷(功能点缺失) normal 一般缺陷(边界情况,格式错误) minor 次要缺陷(界面错误与ui需求不符) trivial 轻微缺陷(必须项无提示,或者提示不规范) """ @allure.severity("normal") def test_case_1(): """ 修改个人姓名为空 """ print("test case 1:修改姓名为空") @allure.severity("critical") def test_case_2(): """ 修改个人姓名为已有人的身份证信息 """ print("test case 2:修改姓名为他人信息") @allure.severity("critical") def test_case_3(): """ 修改个人信息-生日必填项置空 """ print("test case 3:修改生日为空") @allure.severity("blocker") def test_case_4(): """ 修改个人信息-无法保存 """ print("test case 4:无法保存") def test_case_5(): """ 没标记的severity的用例默认为normal """ print("test case 5:不标记") if __name__ == '__main__': # pytest.main(["-vs","test_case_02.py",'--alluredir','./temps']) #只执行指定级别的用例 pytest.main(["-vs", "test_case_02.py", '--alluredir', './temps','--allure-severities','blocker,critical']) time.sleep(2) # 生成json格式报告后等2秒 os.system("allure generate ./temps -o ./reports --clean") # 表示生成的json格式放在temps目录下,生成的报告放在reports目录下, --clean,表示生成报告前先清除原有内容 说明 @allure.severity 设置优先级 没有标记的用例优先级默认为normal 只执行指定级别的用例 pytest.main(["-vs", "test_case_02.py", '--alluredir', './temps','--allure-severities','blocker,critical']) 只执行blocker和critical的用例 6.allure用例描述 使用方法 参数值 参数说明 @allure.epic() epic描述 敏捷里面的概念,对用例或用例集进行描述分类,往下是feature @allure.feature() 模块名称 与epic类似,只是比epic级别低,往下是story @allure.story() 用户故事 与epic类似,只是比feature级别低,往下是title @allure.title(用例的标题) 用例的标题 重命名html报告的用例名称 @allure.testcase() 测试用例的链接地址 与link类似 @allure.issue() 缺陷 与link类似 @allure.description() 用例描述 进行测试用例的描述 @allure.step() 操作步骤 进行测试用例的步骤 @allure.severity() 用例等级 blocker,critical,normal,minor,trivial @allure.link() 链接 定义一个链接,在测试报告展现(推荐使用) @allure.attachment() 附件 报告添加附件 将描述信息加入到用例中 代码 test_case_03.py import os import time import pytest import allure @pytest.fixture(scope="session") def login_fixture(): print("前置条件:登录") @allure.step("步骤1") def step_1(): print("操作步骤%s1"%("-"*30)) @allure.step("步骤2") def step_2(): print("操作步骤2") @allure.step("步骤3") def step_3(): print("操作步骤%s3"%("-"*30)) @allure.epic("epic:大特性,一个描述性标签,大特性1") @allure.feature("测试模块1") class TestDemoAllure(): @allure.testcase("http://127.0.0.1:8080/zentao/testcase-view-6-1.html") @allure.issue("http://127.0.0.1:8080/zentao/bug-view-1.html") @allure.title("用例的标题") @allure.story("用户故事:1") @allure.severity("critical") def test_case_1(self,login_fixture): """ case desc: 1.点文章分类导航标签 -跳转编辑页面 2.编辑页面输入,分类名称,如:上海-悠悠-可以输入 3.点保存按钮保存成功 """ print("测试用例1") step_1() step_2() @allure.story("用户故事:2") def test_case_2(self,login_fixture): """ case desc: 1.点文章分类导航标签 -跳转编辑页面 2.编辑页面输入,分类名称,如:上海-悠悠-可以输入 3.点保存按钮保存成功 """ print("测试用例2") step_1() step_3() @allure.epic("epic对大Story的一个描述性标签,大特性2") @allure.feature("模块2") class TestDemoTwo(): @allure.story("用户故事:3") @allure.severity("critical") def test_case_3(self,login_fixture): """ case desc: 1.点文章分类导航标签 -跳转编辑页面 2.编辑页面输入,分类名称,如:上海-悠悠-可以输入 3.点保存按钮保存成功 """ print("测试用例3") step_1() step_2() @allure.story("用户故事:4") def test_case_4(self,login_fixture): """ case desc: 1.点文章分类导航标签 -跳转编辑页面 2.编辑页面输入,分类名称,如:上海-悠悠-可以输入 3.点保存按钮保存成功 """ print("测试用例4") step_1() step_3() if __name__ == '__main__': pytest.main(["-vs","test_case_03.py",'--alluredir','./temps']) time.sleep(2) # 生成json格式报告后等2秒 os.system("allure generate ./temps -o ./reports --clean") # 表示生成的json格式放在temps目录下,生成的报告放在reports目录下, --clean,表示生成报告前先清除原有内容 7.添加用例步骤详解 代码 common_function.py 通用函数方法 """ 举个常见的测试场景用例 从登录开始,到浏览商品添加购物车,最后下单支付 用例步骤: 1.登录 2.浏览商品 3.添加购物车 4.生成订单 5.支付成功 """ #把上面的每个环节,写成函数放到common_function.py def login(username,password): """登录""" print("前置操作:先登录") def open_goods(): """浏览商品""" print("浏览商品") def add_shopping_cart(goods_id="10086"): """添加购物车""" print("添加购物车") def buy_goods(): """生成订单""" print("生成订单") def pay_goods(): """支付订单""" print("支付订单") test_allure_step.py 测试用例编写用到通用方法 import os import time import pytest import allure from p05_testcase_step.common_function import * #接下来的测试用例设计,登录可以单独那出来,当成前置操作 @pytest.fixture(scope="session") def login_setup(): login(username="zz", password="123456") @allure.feature("功能模块") @allure.story("测试用例小模块-成功案例") @allure.title("测试用例名称:流程性用例,添加测试步骤") def test_add_goods_and_buy(login_setup): """ 用例描述: 前置:登录 用例步骤: 1.浏览商品 2.添加购物车 3.生成订单 4.支付成功 """ with allure.step(title="step1:浏览商品"): open_goods() with allure.step(title="step2:添加购物车"): add_shopping_cart(goods_id="10086") with allure.step(title="step3:生成订单"): buy_goods() with allure.step(title="step4:支付成功"): pay_goods() with allure.step(title="断言"): assert 1==1 if __name__ == '__main__': pytest.main(["-vs","test_allure_step.py",'--alluredir','./temps']) time.sleep(2) # 生成json格式报告后等2秒 os.system("allure generate ./temps -o ./reports --clean") # 表示生成的json格式放在temps目录下,生成的报告放在reports目录下, --clean,表示生成报告前先清除原有内容 另一种写测试步骤的方法 测试步骤也可以用装饰器实现@allure.step 代码 common_function_two.py """ 举个常见的测试场景用例 从登录开始,到浏览商品添加购物车,最后下单支付 用例步骤: 1.登录 2.浏览商品 3.添加购物车 4.生成订单 5.支付成功 """ #把上面的每个环节,写成函数放到common_function.py #测试步骤也可以用装饰器实现@allure.step import allure @allure.step(title="setup:登录") def login(username,password): """登录""" print("前置操作:先登录") @allure.step(title="step:浏览商品") def open_goods(): """浏览商品""" print("浏览商品") @allure.step(title="step:添加购物车") def add_shopping_cart(goods_id="10086"): """添加购物车""" print("添加购物车") @allure.step(title="step:生成订单") def buy_goods(): """生成订单""" print("生成订单") @allure.step(title="step:支付订单") def pay_goods(): """支付订单""" print("支付订单") test_allure_step_two.py import os import time import pytest import allure from p05_testcase_step.common_function_two import * #接下来的测试用例设计,登录可以单独那出来,当成前置操作 @pytest.fixture(scope="session") def login_setup(): login(username="zz", password="123456") @allure.feature("功能模块") @allure.story("测试用例小模块-成功案例2") @allure.title("测试用例名称:流程性用例,添加测试步骤") def test_add_goods_and_buy_2(login_setup): """ 用例描述: 前置:登录 用例步骤: 1.浏览商品 2.添加购物车 3.生成订单 4.支付成功 """ open_goods() add_shopping_cart(goods_id="10086") buy_goods() pay_goods() assert 1==2 if __name__ == '__main__': pytest.main(["-vs","test_allure_step_two.py",'--alluredir','./temps']) time.sleep(2) # 生成json格式报告后等2秒 os.system("allure generate ./temps -o ./reports --clean") # 表示生成的json格式放在temps目录下,生成的报告放在reports目录下, --clean,表示生成报告前先清除原有内容 好处 可以将函数的参数带进报告中,展示出来 8.参数化(parametrize)结合allure.title()生成不同标题报告 allure报告清空上一次运行的记录(--clean-alluredir) allure.dynamic动态生成用例标题 allure添加环境配置(environment) allure报告添加用例失败截图 @pytest.mark.parametrize 表示参数化内容 代码 test_a.py """ 一个简单的pytest参数化案例演示 """ import pytest import allure import time import os def login(username, password): '''登录''' print("输入账号:%s" % username) print("输入密码:%s" % password) # 返回 return {"code": 0, "msg": "success!"} # 测试数据 test_datas = [ ({"username": "yoyo1", "password": "123456"}, "success!"), ({"username": "yoyo2", "password": "123456"}, "failed!"), ({"username": "yoyo3", "password": "123456"}, "success!"), ] @allure.story("登录用例") @pytest.mark.parametrize("test_input,expected", test_datas ) def test_login(test_input, expected): '''测试登录用例''' # 获取函数返回结果 result = login(test_input["username"], test_input["password"]) # 断言 assert result["msg"] == expected if __name__ == '__main__': pytest.main(["-vs","test_a.py",'--alluredir','./temps']) time.sleep(2) # 生成json格式报告后等2秒 os.system("allure generate ./temps -o ./reports --clean") # 表示生成的json格式放在temps目录下,生成的报告放在reports目录下, --clean,表示生成报告前先清除原有内容 这样生成的报告在用例列表里面并不能很友好的展示出每个用例的执行场景,只知道哪个用例报错了。 解决:可以对每个用例加上描述,加一个 ids 参数 代码 test_a_ids.py """ 一个简单的pytest参数化案例演示 """ import pytest import allure import time import os def login(username, password): '''登录''' print("输入账号:%s" % username) print("输入密码:%s" % password) # 返回 return {"code": 0, "msg": "success!"} # 测试数据 test_datas = [ ({"username": "yoyo1", "password": "123456"}, "success!"), ({"username": "yoyo2", "password": "123456"}, "failed!"), ({"username": "yoyo3", "password": "123456"}, "success!"), ] @allure.story("登录用例") @pytest.mark.parametrize("test_input,expected", test_datas, ids=[ "输入正确账号,密码,登录成功", "输入错误账号,密码,登录失败", "输入正确账号,密码,登录成功", ] ) def test_login(test_input, expected): '''测试登录用例''' # 获取函数返回结果 result = login(test_input["username"], test_input["password"]) # 断言 assert result["msg"] == expected if __name__ == '__main__': pytest.main(["-vs","test_a_ids.py",'--alluredir','./temps']) time.sleep(2) # 生成json格式报告后等2秒 os.system("allure generate ./temps -o ./reports --clean") # 表示生成的json格式放在temps目录下,生成的报告放在reports目录下, --clean,表示生成报告前先清除原有内容 也可以用 allure.title("用例描述") 添加用例描述的方式解决 代码 test_a_allure_title.py """ 一个简单的pytest参数化案例演示 """ import pytest import allure import time import os def login(username, password): '''登录''' print("输入账号:%s" % username) print("输入密码:%s" % password) # 返回 return {"code": 0, "msg": "success!"} # 测试数据 test_datas = [ ({"username": "yoyo1", "password": "123456"}, "success!"), ({"username": "yoyo2", "password": "123456"}, "failed!"), ({"username": "yoyo3", "password": "123456"}, "success!"), ] @allure.story("登录用例") @allure.title("用例描述,测试输入:{test_input}") @pytest.mark.parametrize("test_input,expected", test_datas ) def test_login(test_input, expected): '''测试登录用例''' # 获取函数返回结果 result = login(test_input["username"], test_input["password"]) # 断言 assert result["msg"] == expected if __name__ == '__main__': pytest.main(["-vs","test_a_allure_title.py",'--alluredir','./temps']) time.sleep(2) # 生成json格式报告后等2秒 os.system("allure generate ./temps -o ./reports --clean") # 表示生成的json格式放在temps目录下,生成的报告放在reports目录下, --clean,表示生成报告前先清除原有内容 当没有加allure.title()时候,用例的描述就是 item.name 值(也就是上面的 ids 用例的名 称), 如果加了allure.title(),那么用例的描述就是添加的title值,这两个地方取其中的一个。 代码 (源代码)allure_pytest/utils.py def allure_name(item, parameters): name = escape_name(item.name) title = allure_title(item) return title.format(**parameters) if title else name test_a_ids_allure_title.py """ 一个简单的pytest参数化案例演示 """ import pytest import allure import time import os def login(username, password): '''登录''' print("输入账号:%s" % username) print("输入密码:%s" % password) # 返回 return {"code": 0, "msg": "success!"} # 测试数据 test_datas = [ ({"username": "yoyo1", "password": "123456"}, "success!"), ({"username": "yoyo2", "password": "123456"}, "failed!"), ({"username": "yoyo3", "password": "123456"}, "success!"), ] @allure.story("登录用例") @allure.title("用例描述,测试输入:{test_input}") @pytest.mark.parametrize("test_input,expected", test_datas, ids=[ "输入正确账号,密码,登录成功", "输入错误账号,密码,登录失败", "输入正确账号,密码,登录成功", ] ) def test_login(test_input, expected): '''测试登录用例''' # 获取函数返回结果 result = login(test_input["username"], test_input["password"]) # 断言 assert result["msg"] == expected if __name__ == '__main__': pytest.main(["-vs","test_a_ids_allure_title.py",'--alluredir','./temps']) time.sleep(2) # 生成json格式报告后等2秒 os.system("allure generate ./temps -o ./reports --clean") # 表示生成的json格式放在temps目录下,生成的报告放在reports目录下, --clean,表示生成报告前先清除原有内容 结合上面两种实现方式,把用例描述当成一个测试输入的参数,继续优化 代码 test_a_ids_allure_title_youhua.py """ 一个简单的pytest参数化案例演示 """ import pytest import allure import time import os def login(username, password): '''登录''' print("输入账号:%s" % username) print("输入密码:%s" % password) # 返回 return {"code": 0, "msg": "success!"} # 测试数据 test_datas = [ ({"username": "yoyo1", "password": "123456"}, "success!", "输入正确账号,密码,登录成功"), ({"username": "yoyo2", "password": "123456"}, "failed!", "输入错误账号,密码,登录失败"), ({"username": "yoyo3", "password": "123456"}, "success!", "输入正确账号,密码,登录成功"), ] @allure.story("登录用例") @allure.title("{title}") @pytest.mark.parametrize("test_input,expected,title", test_datas ) def test_login(test_input, expected, title): '''测试登录用例''' # 获取函数返回结果 result = login(test_input["username"], test_input["password"]) # 断言 assert result["msg"] == expected if __name__ == '__main__': pytest.main(["-vs","test_a_ids_allure_title_youhua.py",'--alluredir','./temps']) time.sleep(2) # 生成json格式报告后等2秒 os.system("allure generate ./temps -o ./reports --clean") # 表示生成的json格式放在temps目录下,生成的报告放在reports目录下, --clean,表示生成报告前先清除原有内容 使用allure.dynamic可以给用例动态添加内容 属性有 allure.dynamic.feature allure.dynamic.link allure.dynamic.issue allure.dynamic.testcase allure.dynamic.story allure.dynamic.title allure.dynamic.description 用法 代码 test_a_ids_allure_title_youhua_dynamic.py """ 一个简单的pytest参数化案例演示 """ import pytest import allure import time import os def login(username, password): '''登录''' print("输入账号:%s" % username) print("输入密码:%s" % password) # 返回 return {"code": 0, "msg": "success!"} # 测试数据 test_datas = [ ({"username": "yoyo1", "password": "123456"}, "success!", "输入正确账号,密码,登录成功","模块1","禅道链接1"), ({"username": "yoyo2", "password": "123456"}, "failed!", "输入错误账号,密码,登录失败","模块2","禅道链接2"), ({"username": "yoyo3", "password": "123456"}, "success!", "输入正确账号,密码,登录成功","模块3","禅道链接3"), ] @allure.story("登录用例") @pytest.mark.parametrize("test_input,expected,title,feature,link_url", test_datas ) def test_login(test_input, expected, title,feature,link_url): '''测试登录用例''' # 获取函数返回结果 result = login(test_input["username"], test_input["password"]) allure.dynamic.feature(feature) allure.dynamic.link(url=link_url) # allure.dynamic.issue() # allure.dynamic.testcase() # allure.dynamic.story() allure.dynamic.title(test_title=title) # allure.dynamic.description() # 断言 assert result["msg"] == expected if __name__ == '__main__': pytest.main(["-vs","test_a_ids_allure_title_youhua_dynamic.py",'--alluredir','./temps']) time.sleep(2) # 生成json格式报告后等2秒 os.system("allure generate ./temps -o ./reports --clean") # 表示生成的json格式放在temps目录下,生成的报告放在reports目录下, --clean,表示生成报告前先清除原有内容 先配置一个文件environment.properties,放在和测试用例运行脚本同目录下 environment.properties systemVersion=win10 pythonVersion=3.6.0 allureVersion=2.13.0 baseUrl=http://192.168.1.x:8080 projectName=test author=YOYO email=283340479@qq.com blog=https://www.cnblogs.com/yoyoketang/ 或者配置文件environment.xml <environment> <parameter> <key>Browser</key> <value>Chrome</value> </parameter> <parameter> <key>Browser.Version</key> <value>63.0</value> </parameter> <parameter> <key>Stand</key> <value>Production</value> </parameter> </environment> 运行命令 配置文件不支持中文,否则会报乱码 pytest.main(["-vs","test_a_ids_allure_title_youhua_dynamic.py",'--alluredir','./temps']) time.sleep(2) # 生成json格式报告后等2秒 os.system("copy environment.properties temps\environment.properties") os.system("allure generate ./temps -o ./reports --clean") # 表示生成的json格式放在temps目录下,生成的报告放在reports目录下, --clean,表示生成报告前先清除原有内容 代码 test_a_ids_allure_title_youhua_dynamic.py import pytest import allure import time import os def login(username, password): '''登录''' print("输入账号:%s" % username) print("输入密码:%s" % password) # 返回 return {"code": 0, "msg": "success!"} # 测试数据 test_datas = [ ({"username": "yoyo1", "password": "123456"}, "success!", "输入正确账号,密码,登录成功","模块1","禅道链接1"), ({"username": "yoyo2", "password": "123456"}, "failed!", "输入错误账号,密码,登录失败","模块2","禅道链接2"), ({"username": "yoyo3", "password": "123456"}, "success!", "输入正确账号,密码,登录成功","模块3","禅道链接3"), ] @allure.story("登录用例") @pytest.mark.parametrize("test_input,expected,title,feature,link_url", test_datas ) def test_login(test_input, expected, title,feature,link_url): '''测试登录用例''' # 获取函数返回结果 result = login(test_input["username"], test_input["password"]) allure.dynamic.feature(feature) allure.dynamic.link(url=link_url) # allure.dynamic.issue() # allure.dynamic.testcase() # allure.dynamic.story() allure.dynamic.title(test_title=title) # allure.dynamic.description() # 断言 assert result["msg"] == expected if __name__ == '__main__': pytest.main(["-vs","test_a_ids_allure_title_youhua_dynamic.py",'--alluredir','./temps']) time.sleep(2) # 生成json格式报告后等2秒 os.system("copy environment.properties temps\environment.properties") #复制环境变量配置文件 os.system("allure generate ./temps -o ./reports --clean") # 表示生成的json格式放在temps目录下,生成的报告放在reports目录下, --clean,表示生成报告前先清除原有内容
posted on 2022-04-15 10:28  大话人生  阅读(297)  评论(0编辑  收藏  举报