Pytest进阶三阶段
Pytest相关
主流自动化测试框架设计体系
编程语言的选择:Python(80%)、java(20%)
自动化模块:selenium/appium/requests
设计模式:关键字驱动/POM
-------------------------------------------初阶-----------------------------------------------
1、 关键字驱动
- 原始代码分离为:代码与数据
- 二次分离代码:行为代码与测试代码
- 数据驱动行为代码,生成:最终的基于关键字驱动的测试代码
作用:从而更加便捷的进行自动化测试代码的管理,以及提高自动化的复用性,让使用者更加容易理解和使用自动化。
-
关键字驱动+pytest编码实现
目录
key_word_web.py
""" web端的关键字驱动类: 结构中属于行为代码层,主要的目的是作为一个工具类的角色, 在需要时遇到这些工具的时候,通过这个类实现;如: 大型超市---购买工具---使用工具 selenium---关键字---web自动化 工具箱一般包含有需要的常规操作: 输入、点击、启动。。。 单独的工具类的存在是没有意义的,一定需要关联到实际应用,才能产生价值 """ #引用模块 from selenium import webdriver from time import sleep #定义工具类 class WebKeys: #构造函数,调用类,就会执行 #创建webdriver驱动 def __init__(self): self.driver = webdriver.Chrome() #访问url def open(self,url): self.driver.get(url) #退出 def quit(self): self.driver.quit() #元素定位 def locator(self,name,value): """ :param name: 定位方式,如xpath、id、name等8种定位方式 :param value: 定位元素的属性值 :return: 输入后即可调用使用 """ return self.driver.find_element(name,value) #输入 def input(self,name,value,txt): el = self.locator(name,value)#定位元素 el.clear() #清除下输入框内容 el.send_keys(txt) #输入内容 #强制等待 def wait(self,time_): sleep(time_)
test_case01.py
import pytest from demo.key_word.key_word_web import * def test_login(): wk = WebKeys() wk.open('http://www.baidu.com') wk.wait(1) wk.input('xpath',"//*[@id='kw']","狗狗币") wk.wait(3) wk.quit() if __name__ == '__main__': pytest.main(['test_case01.py'])
运行结果:
============================= test session starts ============================= platform win32 -- Python 3.8.5, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 rootdir: C:\Users\11130\PycharmProjects\pythonProject2\demo\test_case plugins: html-3.1.1, metadata-1.11.0 collected 1 item test_case01.py . [100%] ============================= 1 passed in 10.78s ==============================
-------------------------------------------中阶-----------------------------------------------
2、数据驱动
——将测试过程中所有的测试数据进行提取、保存以及管理,提升框架的可维护性(就是将txt、Excel、yaml、json、py、csv、ini等数据提取后进行测试)
-
yaml 数据驱动
- yaml 安装:pip install pyyaml
- yaml 是一种文件格式,可以在Pycharm中创建后缀为yaml的文件,类似于xml
-
yaml应用
- “ - ”: list(列表)标签
- “ :”:dict(字典)标签
关键字驱动+pytest+yaml数据驱动编码实现
测试用例管理工具:
- Unittest: Python语言的标准的测试框架
- Pytest: 目前拥有800+插件的第三方库测试框架
测试报告:HTMLTestRunner、Allure
key_word_web.py
#引用模块 from selenium import webdriver from time import sleep #定义工具类 class WebKeys: #构造函数,调用类,就会执行 #创建webdriver驱动 def __init__(self): self.driver = webdriver.Chrome() #访问url def open(self,url): self.driver.get(url) #退出 def quit(self): self.driver.quit() #元素定位 def locator(self,name,value): """ :param name: 定位方式,如xpath、id、name等8种定位方式 :param value: 定位元素的属性值 :return: 输入后即可调用使用 """ return self.driver.find_element(name,value) #输入 def input(self,name,value,txt): el = self.locator(name,value)#定位元素 el.clear() #清除下输入框内容 el.send_keys(txt) #输入内容 #强制等待 def wait(self,time_): sleep(time_)
(1)@pytest.mark.parametrize:数据驱动可以直接传递数值
test_case02.py
import pytest from demo.key_word.key_word_web import * #需要数据的测试用例:数据驱动可以直接传递数值 @pytest.mark.parametrize("a",['aaa','bbb','ccc'])#会把数据依次把list中数据传递给下边函数中参数a,执行参数化测试 def test_login(a): wk = WebKeys() wk.open('http://www.baidu.com') wk.wait(1) wk.input('xpath',"//*[@id='kw']",a) wk.wait(3) wk.quit() if __name__ == '__main__': pytest.main(['test_case02.py'])
(2)@pytest.mark.parametrize:通过函数的形式将结果生成并返回
代码思路:
-
yaml文件中编写三条数据
-
封装读取yaml的函数
-
使用@pytest.mark.parametrize()装饰器来调用数据
- 最终实现参数化调用执行
目录
baidu.yaml
-
url: http://www.baidu.com #冒号后边加一个空格
name: xpath
value: //*[@id="kw"]
txt: 狗狗币
-
url: http://www.baidu.com
name: xpath
value: //*[@id="kw"]
txt: selenium
-
url: http://www.baidu.com
name: xpath
value: //*[@id="kw"]
txt: pytest
yaml_driver.py
import yaml def load_yaml(path): file = open(path,'r',encoding='utf-8') data = yaml.load(file,yaml.FullLoader)#读取yaml文件,yaml.FullLoader加载完整的yaml文件,避免代码的任意执行 return data
test_case02.py
import pytest from demo.key_word.key_word_web import WebKeys from demo.data_driver import yaml_driver # 通过函数的形式将结果生成并返回 @pytest.mark.parametrize('data', yaml_driver.load_yaml('../data/baidu.yaml')) #读取yaml文件 def test_login(data): wk = WebKeys() wk.open(data['url']) wk.wait(1) wk.input(data["name"], data["value"], data["txt"]) wk.wait(3) wk.quit() if __name__ == '__main__': pytest.main(['test_case02.py'])
-------------------------------------------高阶-----------------------------------------------
配置管理:CMO(配置管理员)
-
环境(服务器、数据库、tomcat等)
-
日志:Logging、nnlog,traceback(获取报错信息),locals(获取所有参数)
-
代码管理:Git、svn——代码的调整
- 持续集成:Jenkins
- 定时构建(自定义定时的执行自动化脚本)
- 任务触发构建mmp(开发提交新版本到特定路径下,就可以:通过Jenkins自动化的下载新版本--->部署到测试环境里面--->启动测试框架--->执行新版本的自动化回归测试--->产生测试报告--->当时发给相关人员
-----------------------------------优化------------------------------------
测试用例的并发:多任务并发处理机制,异步形态实现用例读取与执行(多个用例同时执行)
测试框架分布式的结构设计:主从节点(通过路由节点下发测试任务,由子节点执行测试结果,最终集成测试完整结果形成一体化的测试报告)。
总结:
- 自动化测试技能的学习——编码是第二重要的内容,第一重要的一定是设计思维。
- 测试行业需求的核心技术是测试框架,所以我们需要学会研发测试框架
unittest
- Unitest是Python标准库中自带的单元测试框架,Unittest有时候也被称为PyUnit,就像JUnit是Java语言的标准单元测试框架一样,Unittest则是Python语言的标准单元测试框架
- Unittest支持自动化测试,测试用例的初始化、关闭和测试用例的聚合等功能
- Unittest有一个很重要的特性:通过类(class)的方式,将测试用例组织在一起
(1)断言通过
import unittest #要应用unittest框架:必须在类名继承unittest.TestCase class unitDeno(unittest.TestCase): #普通函数:封装逻辑代码,便于在测试用例中进行调用 def test_login(self): print('这是login函数') self.assertEqual(123,123,msg='断言失败') #运行测试用例 if __name__ == '__main__': #unittest执行测试用例 unittest.main()
结果:
Launching unittests with arguments python -m unittest C:/Users/11130/PycharmProjects/pythonProject2/demo/unittest_demo/unittest_demo.py in C:\Users\11130\PycharmProjects\pythonProject2\demo\unittest_demo Ran 1 test in 0.002s OK 这是login函数 进程已结束,退出代码为 0
(2)断言不通过
#导入unittest模块 import unittest #要应用unittest框架:必须在类名继承unittest.TestCase class unitDeno(unittest.TestCase): #普通函数:封装逻辑代码,便于在测试用例中进行调用 def test_login(self): print('这是login函数') self.assertEqual(1,123,msg='断言失败') #运行测试用例 if __name__ == '__main__': #unittest执行测试用例 unittest.main()
结果:
Launching unittests with arguments python -m unittest C:/Users/11130/PycharmProjects/pythonProject2/demo/unittest_demo/unittest_demo.py in C:\Users\11130\PycharmProjects\pythonProject2\demo\unittest_demo 这是login函数 断言失败 123 != 1 预期:1 实际:123 <点击以查看差异> Traceback (most recent call last): File "C:\Program Files\JetBrains\PyCharm 2020.3.1\plugins\python\helpers\pycharm\teamcity\diff_tools.py", line 32, in _patched_equals old(self, first, second, msg) File "C:\Users\11130\AppData\Local\Programs\Python\Python38\lib\unittest\case.py", line 912, in assertEqual assertion_func(first, second, msg=msg) File "C:\Users\11130\AppData\Local\Programs\Python\Python38\lib\unittest\case.py", line 905, in _baseAssertEqual raise self.failureException(msg) AssertionError: 1 != 123 : 断言失败 During handling of the above exception, another exception occurred: Traceback (most recent call last): File "C:\Users\11130\AppData\Local\Programs\Python\Python38\lib\unittest\case.py", line 60, in testPartExecutor yield File "C:\Users\11130\AppData\Local\Programs\Python\Python38\lib\unittest\case.py", line 676, in run self._callTestMethod(testMethod) File "C:\Users\11130\AppData\Local\Programs\Python\Python38\lib\unittest\case.py", line 633, in _callTestMethod method() File "C:\Users\11130\PycharmProjects\pythonProject2\demo\unittest_demo\unittest_demo.py", line 10, in test_login self.assertEqual(1,123,msg='断言失败') Ran 1 test in 0.004s FAILED (failures=1) 进程已结束,退出代码为 1 断言失败 断言失败 断言失败
Pytest
Pytest是Python的另外一个第三方单元测试库。它的目的是让单元测试变得更容易,并且也能扩展到支持应用层面复杂的功能测试。
pytest特性:
-
支持用简单的assert语句实现丰富的断言,无需复杂的self.assert*函数
-
自动识别测试模块和测试函数
-
模块化夹具有以管理各类测试资源
-
对unittest完全兼容,对nose基本兼容
-
支持Python3和pypy3
-
丰富的插件生态,目前已有各式各样的插件800多个,社区繁荣
Pytest VS Unittest
Unittest | Pytest | |
用例编写规范 |
1)测试文件必须先import unittest 2)测试类必须继承Unittest.TestCase 3)测试方法必须以”test_”开头 4)测试类必须要有unittest.main()方法 |
1)测试文件名必须以“test_”开头或者“_test”结尾(如:test_ab.py) 2)测试方法必须以“test_”开头 3)测试类名以“Test_”开头 * 如若不想以test来进行识别,可在pytest.ini中自定义 |
用例分类执行 | 默认执行全部用例,也可通过加载testsuit,执行部分用例 | 可以通过@pytest.mark来标记类和方法,pytest.main加入参数(“-m")可以只运行标记的类和方法 |
用例前置和后置 | 提供了setUp/tearDown,只能针对所有的用例 | pytest中fixture显然更加灵活。可以任意自定义函数,只要加上@pytest.fixture()装饰器,那么被封装的方法就可以被使用 |
参数化 | 需依赖ddt库 | 使用@pytest.mark.parametrize()装饰器 |
断言 | 很多断言格式(assertEqual、asserIn、assertTrue、assertFalse等) | 只有assert一个表达式,用起来比较方便 |
报告 | 使用HTMLTestRunnerNew库、BeautifulReport模块 | 有pytest-HTML、allure插件 |
失败重跑 | 无此功能 | pytest支持用例执行失败重跑,pytest-rerunfailures插件(需要pip安装) |
1、pyest中设置用例执行失败的最大次数: --maxfail=n
import pytest def test_01(): print("测试用例一执行成功") assert 1==1 def test_02(): print("测试用例二执行成功") assert 1==2 def test_03(): print("测试用例三执行成功") assert 1==3 def test_04(): print("测试用例四执行成功") assert 1==1 if __name__ == '__main__': pytest.main(['-s','--maxfail=2']) #执行用例最大失败次数maxfail=2
执行结果:
============================= test session starts ============================= platform win32 -- Python 3.8.5, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 rootdir: C:\Users\11130\PycharmProjects\pythonProject2\demo\pytest_baseuser plugins: html-3.1.1, metadata-1.11.0 collected 4 items test_fail.py 测试用例一执行成功 .测试用例二执行成功 F测试用例三执行成功 F ================================== FAILURES =================================== ___________________________________ test_02 ___________________________________ def test_02(): print("测试用例二执行成功") > assert 1==2 E assert 1 == 2 test_fail.py:11: AssertionError ___________________________________ test_03 ___________________________________ def test_03(): print("测试用例三执行成功") > assert 1==3 E assert 1 == 3 test_fail.py:15: AssertionError =========================== short test summary info =========================== FAILED test_fail.py::test_02 - assert 1 == 2 FAILED test_fail.py::test_03 - assert 1 == 3 !!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 2 failures !!!!!!!!!!!!!!!!!!!!!!!!!! ========================= 2 failed, 1 passed in 0.13s ========================= 进程已结束,退出代码为 0
添加--maxfail=2,因为计算机是从0开始计数的,因此会执行3条用例,第四条test_04()用例将不会被执行。
2、用例执行失败一次,则退出测试:-x
import pytest def test_01(): print("测试用例一执行成功") assert 1==1 def test_02(): print("测试用例二执行成功") assert 1==2 def test_03(): print("测试用例三执行成功") assert 1==3 def test_04(): print("测试用例四执行成功") assert 1==1 if __name__ == '__main__': pytest.main(['-x'])
结果:
============================= test session starts ============================= platform win32 -- Python 3.8.5, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 rootdir: C:\Users\11130\PycharmProjects\pythonProject2\demo\pytest_baseuser plugins: html-3.1.1, metadata-1.11.0 collected 4 items test_fail.py .F ================================== FAILURES =================================== ___________________________________ test_02 ___________________________________ def test_02(): print("测试用例二执行成功") > assert 1==2 E assert 1 == 2 test_fail.py:9: AssertionError ---------------------------- Captured stdout call ----------------------------- 测试用例二执行成功 =========================== short test summary info =========================== FAILED test_fail.py::test_02 - assert 1 == 2 !!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!! ========================= 1 failed, 1 passed in 0.09s ========================= 进程已结束,退出代码为 0
我们可以看出test_02()是断言失败的,test_03、test_04是没有运行的。当加上“-x”命令后,遇到断言失败时,则会退出程序,不继续执行了。
3、多进程运行用例
——用例较多了,为了缩短用例执行的时长,就可以使用多进程用例来执行。
安装:pip install pytest-xdist
运行方式:pytest -n NUMCPUS
import pytest def test_case01(): print("测试用例一执行成功") assert 1==1 def test_case02(): print("测试用例二执行成功") assert 1==1 def test_case03(): print("测试用例三执行成功") assert 1==3 def test_case04(): print("测试用例四执行成功") assert 1==4 if __name__ == '__main__': #将测试发送给多个CPU pytest.main(['-n','auto','test_many.py'])##'-n','2'——表示指定2个CPU来跑 #使用与计算机具有cpu一样的进程 pytest.main(['-n','auto','test_many.py'])#'-n','auto'——表示使用电脑有几核,就会创建几个CPU
2个CPU结果:
我们可看出会初始化2个CPU,会把测试用例分别给到2个CPU同时执行。相当于本来是1个人在干活,现在是又找来了一个人,现在是2个人一起干活了。与计算机具有cpu一样的进程结果:
============================= test session starts ============================= platform win32 -- Python 3.8.5, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 rootdir: C:\Users\11130\PycharmProjects\pythonProject2\demo\pytest_baseuser plugins: forked-1.4.0, html-3.1.1, metadata-1.11.0, xdist-2.5.0 gw0 I / gw1 I / gw2 I / gw3 I / gw4 I / gw5 I / gw6 I / gw7 I gw0 [4] / gw1 [4] / gw2 [4] / gw3 [4] / gw4 [4] / gw5 [4] / gw6 [4] / gw7 [4] ..FF [100%] ================================== FAILURES =================================== _________________________________ test_case03 _________________________________ [gw2] win32 -- Python 3.8.5 C:\Users\11130\AppData\Local\Programs\Python\Python38\python.exe def test_case03(): print("测试用例三执行成功") > assert 1==3 E assert 1 == 3 test_many.py:13: AssertionError ---------------------------- Captured stdout call ----------------------------- 测试用例三执行成功 _________________________________ test_case04 _________________________________ [gw3] win32 -- Python 3.8.5 C:\Users\11130\AppData\Local\Programs\Python\Python38\python.exe def test_case04(): print("测试用例四执行成功") > assert 1==4 E assert 1 == 4 test_many.py:17: AssertionError ---------------------------- Captured stdout call ----------------------------- 测试用例四执行成功 =========================== short test summary info =========================== FAILED test_many.py::test_case03 - assert 1 == 3 FAILED test_many.py::test_case04 - assert 1 == 4 ========================= 2 failed, 2 passed in 2.68s ========================= 进程已结束,退出代码为 0
4、用例失败重跑pytest-rerunfailures
——是属于pytest插件,用例执行失败后会重新执行,以消除间歇性故障。
安装:pip install pytest-rerunfailures
安装要求:
- 需是python3.5-3.8或pypy3)
- pytest5.0以上的版本
源码:https://github.com/pytest-dev/pytest-rerunfailures
其中pytest-rerunfailures有2种用法,一种是装饰器的方法,另一种是命令行参数的方法。
命令行方法
(1)重新运行所有测试用例,使用--reruns命令,并自定义失败用例运行的最大测试
import pytest def test_case01(): assert 1==2 def test_case02(): assert 1==3 def test_case03(): assert 1==3 def test_case04(): assert 1==4 if __name__ == '__main__': #重新运行所有测试用例,使用--reruns命令行,并自定义失败用例运行的最大测试 pytest.main(['--reruns','5','test_rerun.py'])
结果:
(2)在2次重跑之间增加延迟时间,可使用:--reruns-delay,可自定义秒数
- 加上--reruns-delay后,运行完一次都会根据自定义的时间强制等待,等待时间过了继续执行下一条用例
import pytest def test_case01(): assert 1==2 def test_case02(): assert 1==3 if __name__ == '__main__': #要在2次重跑之间增加延迟时间,可使用:--reruns-delay,可自定义秒数 pytest.main(['--reruns','2','--reruns-delay','1','test_rerun.py'])
装饰器方法
import pytest #在类中定义失败了重新跑几次,间隔多少秒 @pytest.mark.flaky(reruns=2,reruns_delay=1) class Test01: def test_case01(self): print('===test_case01===') assert 1==2 def test_case02(self): print('===test_case02===') assert 1==3 if __name__ == '__main__': pytest.main(['-s','test_rerun.py'])
结果:
扑捉报错信息:traceback
pytest --showlocals # show local variables in tracebacks在回溯中显示局部变量 pytest -l # show local variables (shortcut)显示局部变量(快捷方式) pytest --tb=auto #(default) 'long' tracebacks for the first and last (默认)第一个和最后一个的“长”回溯,添加上并没什么卵用 pytest --tb=long # exhaustive, informative traceback formatting详尽的、信息丰富的回溯格式 pytest --tb=short # shorter traceback format更短的回溯格式 pytest --tb=line # only one line per failure每次失败只有一行 pytest --tb=native # Python standard library formatting Python标准库格式化 pytest --tb=no # no traceback at all没有回溯 pytest --full-trace # 显示最全的报错信息
实操练习:
(1)--showlocals :在回溯中显示局部变量
(2)pytest -l:显示局部变量(快捷方式)
import pytest def test_01(): print("用例执行成功") def test_02(): a = 1 assert a == 2 #增加一个报错 if __name__ == '__main__': pytest.main(['-s', '--showlocals', 'test_traceback.py']) pytest.main(['-s','-l','test_traceback.py'])
结果:
(3)--tb=short:更短的回溯格式(只显示断言assert相关部分)
import pytest def test_01(): a = 1 assert a == 2 def test_02(): a = 1 assert a == 3 def test_03(): a = 1 assert a == 4 if __name__ == '__main__': pytest.main(['-s','--tb=short','test_traceback.py'])
结果对比:
(4)--tb=line:每次失败只有一行(失败过多时,可先使用,在使用看全部的)
import pytest def test_01(): a = 1 assert a == 2 def test_02(): a = 1 assert a == 3 def test_03(): a = 1 assert a == 4 if __name__ == '__main__': pytest.main(['-s','--tb=line','test_traceback.py'])
结果对比:
(5)--tb=native:Python标准库格式
import pytest def test_01(): a = 1 assert a == 2 def test_02(): a = 1 assert a == 3 def test_03(): a = 1 assert a == 4 if __name__ == '__main__': pytest.main(['-s','--tb=native','test_traceback.py'])
结果对比:
(6)--tb=no:不显示回溯信息
import pytest def test_01(): a = 1 assert a == 2 def test_02(): a = 1 assert a == 3 def test_03(): a = 1 assert a == 4 if __name__ == '__main__': pytest.main(['-s','--tb=no','test_traceback.py'])
结果对比 :
(7)--full-trace :显示最全的报错信息(包含了所调用到的源代码的具体信息)
import pytest def test_01(): a = 1 assert a == 2 if __name__ == '__main__': pytest.main(['-s','--full-trace','test_traceback.py'])
结果:
C:\Users\11130\AppData\Local\Programs\Python\Python38\python.exe C:/Users/11130/PycharmProjects/pythonProject2/demo/pytest_baseuser/test_traceback.py ============================= test session starts ============================= platform win32 -- Python 3.8.5, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 rootdir: C:\Users\11130\PycharmProjects\pythonProject2\demo\pytest_baseuser plugins: forked-1.4.0, html-3.1.1, metadata-1.11.0, rerunfailures-10.2, xdist-2.5.0 collected 1 item test_traceback.py F ================================== FAILURES =================================== ___________________________________ test_01 ___________________________________ cls = <class '_pytest.runner.CallInfo'> func = <function call_runtest_hook.<locals>.<lambda> at 0x000001CE01413AF0> when = 'call' reraise = (<class '_pytest.outcomes.Exit'>, <class 'KeyboardInterrupt'>) @classmethod def from_call( cls, func: "Callable[[], TResult]", when: "Literal['collect', 'setup', 'call', 'teardown']", reraise: Optional[ Union[Type[BaseException], Tuple[Type[BaseException], ...]] ] = None, ) -> "CallInfo[TResult]": excinfo = None start = timing.time() precise_start = timing.perf_counter() try: > result: Optional[TResult] = func() ..\..\..\..\AppData\Local\Programs\Python\Python38\lib\site-packages\_pytest\runner.py:311: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ > lambda: ihook(item=item, **kwds), when=when, reraise=reraise ) ..\..\..\..\AppData\Local\Programs\Python\Python38\lib\site-packages\_pytest\runner.py:255: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <_HookCaller 'pytest_runtest_call'>, args = () kwargs = {'item': <Function test_01>}, argname = 'item', firstresult = False def __call__(self, *args, **kwargs): if args: raise TypeError("hook calling supports only keyword arguments") assert not self.is_historic() # This is written to avoid expensive operations when not needed. if self.spec: for argname in self.spec.argnames: if argname not in kwargs: notincall = tuple(set(self.spec.argnames) - kwargs.keys()) warnings.warn( "Argument(s) {} which are declared in the hookspec " "can not be found in this hook call".format(notincall), stacklevel=2, ) break firstresult = self.spec.opts.get("firstresult") else: firstresult = False > return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult) ..\..\..\..\AppData\Local\Programs\Python\Python38\lib\site-packages\pluggy\_hooks.py:265: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <_pytest.config.PytestPluginManager object at 0x000001CE7FF29400> hook_name = 'pytest_runtest_call' methods = [<HookImpl plugin_name='runner', plugin=<module '_pytest.runner' from 'C:\\Users\\11130\\AppData\\Local\\Programs\\Pyt...from 'C:\\Users\\11130\\AppData\\Local\\Programs\\Python\\Python38\\lib\\site-packages\\_pytest\\threadexception.py'>>] kwargs = {'item': <Function test_01>}, firstresult = False def _hookexec(self, hook_name, methods, kwargs, firstresult): # called from all hookcaller instances. # enable_tracing will set its own wrapping function at self._inner_hookexec > return self._inner_hookexec(hook_name, methods, kwargs, firstresult) ..\..\..\..\AppData\Local\Programs\Python\Python38\lib\site-packages\pluggy\_manager.py:80: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ hook_name = 'pytest_runtest_call' hook_impls = [<HookImpl plugin_name='runner', plugin=<module '_pytest.runner' from 'C:\\Users\\11130\\AppData\\Local\\Programs\\Pyt...from 'C:\\Users\\11130\\AppData\\Local\\Programs\\Python\\Python38\\lib\\site-packages\\_pytest\\threadexception.py'>>] caller_kwargs = {'item': <Function test_01>}, firstresult = False def _multicall(hook_name, hook_impls, caller_kwargs, firstresult): """Execute a call into multiple python functions/methods and return the result(s). ``caller_kwargs`` comes from _HookCaller.__call__(). """ __tracebackhide__ = True results = [] excinfo = None try: # run impl and wrapper setup functions in a loop teardowns = [] try: for hook_impl in reversed(hook_impls): try: args = [caller_kwargs[argname] for argname in hook_impl.argnames] except KeyError: for argname in hook_impl.argnames: if argname not in caller_kwargs: raise HookCallError( f"hook call must provide argument {argname!r}" ) if hook_impl.hookwrapper: try: gen = hook_impl.function(*args) next(gen) # first yield teardowns.append(gen) except StopIteration: _raise_wrapfail(gen, "did not yield") else: res = hook_impl.function(*args) if res is not None: results.append(res) if firstresult: # halt further impl calls break except BaseException: excinfo = sys.exc_info() finally: if firstresult: # first result hooks return a single value outcome = _Result(results[0] if results else None, excinfo) else: outcome = _Result(results, excinfo) # run all wrapper post-yield blocks for gen in reversed(teardowns): try: gen.send(outcome) _raise_wrapfail(gen, "has second yield") except StopIteration: pass > return outcome.get_result() ..\..\..\..\AppData\Local\Programs\Python\Python38\lib\site-packages\pluggy\_callers.py:60: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <pluggy._result._Result object at 0x000001CE0141B640> def get_result(self): """Get the result(s) for this hook call. If the hook was marked as a ``firstresult`` only a single value will be returned otherwise a list of results. """ __tracebackhide__ = True if self._excinfo is None: return self._result else: ex = self._excinfo > raise ex[1].with_traceback(ex[2]) ..\..\..\..\AppData\Local\Programs\Python\Python38\lib\site-packages\pluggy\_result.py:60: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ hook_name = 'pytest_runtest_call' hook_impls = [<HookImpl plugin_name='runner', plugin=<module '_pytest.runner' from 'C:\\Users\\11130\\AppData\\Local\\Programs\\Pyt...from 'C:\\Users\\11130\\AppData\\Local\\Programs\\Python\\Python38\\lib\\site-packages\\_pytest\\threadexception.py'>>] caller_kwargs = {'item': <Function test_01>}, firstresult = False def _multicall(hook_name, hook_impls, caller_kwargs, firstresult): """Execute a call into multiple python functions/methods and return the result(s). ``caller_kwargs`` comes from _HookCaller.__call__(). """ __tracebackhide__ = True results = [] excinfo = None try: # run impl and wrapper setup functions in a loop teardowns = [] try: for hook_impl in reversed(hook_impls): try: args = [caller_kwargs[argname] for argname in hook_impl.argnames] except KeyError: for argname in hook_impl.argnames: if argname not in caller_kwargs: raise HookCallError( f"hook call must provide argument {argname!r}" ) if hook_impl.hookwrapper: try: gen = hook_impl.function(*args) next(gen) # first yield teardowns.append(gen) except StopIteration: _raise_wrapfail(gen, "did not yield") else: > res = hook_impl.function(*args) ..\..\..\..\AppData\Local\Programs\Python\Python38\lib\site-packages\pluggy\_callers.py:39: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ item = <Function test_01> def pytest_runtest_call(item: Item) -> None: _update_current_test_var(item, "call") try: del sys.last_type del sys.last_value del sys.last_traceback except AttributeError: pass try: item.runtest() except Exception as e: # Store trace info to allow postmortem debugging sys.last_type = type(e) sys.last_value = e assert e.__traceback__ is not None # Skip *this* frame sys.last_traceback = e.__traceback__.tb_next > raise e ..\..\..\..\AppData\Local\Programs\Python\Python38\lib\site-packages\_pytest\runner.py:170: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ item = <Function test_01> def pytest_runtest_call(item: Item) -> None: _update_current_test_var(item, "call") try: del sys.last_type del sys.last_value del sys.last_traceback except AttributeError: pass try: > item.runtest() ..\..\..\..\AppData\Local\Programs\Python\Python38\lib\site-packages\_pytest\runner.py:162: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <Function test_01> def runtest(self) -> None: """Execute the underlying test function.""" > self.ihook.pytest_pyfunc_call(pyfuncitem=self) ..\..\..\..\AppData\Local\Programs\Python\Python38\lib\site-packages\_pytest\python.py:1641: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <_HookCaller 'pytest_pyfunc_call'>, args = () kwargs = {'pyfuncitem': <Function test_01>}, argname = 'pyfuncitem' firstresult = True def __call__(self, *args, **kwargs): if args: raise TypeError("hook calling supports only keyword arguments") assert not self.is_historic() # This is written to avoid expensive operations when not needed. if self.spec: for argname in self.spec.argnames: if argname not in kwargs: notincall = tuple(set(self.spec.argnames) - kwargs.keys()) warnings.warn( "Argument(s) {} which are declared in the hookspec " "can not be found in this hook call".format(notincall), stacklevel=2, ) break firstresult = self.spec.opts.get("firstresult") else: firstresult = False > return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult) ..\..\..\..\AppData\Local\Programs\Python\Python38\lib\site-packages\pluggy\_hooks.py:265: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <_pytest.config.PytestPluginManager object at 0x000001CE7FF29400> hook_name = 'pytest_pyfunc_call' methods = [<HookImpl plugin_name='python', plugin=<module '_pytest.python' from 'C:\\Users\\11130\\AppData\\Local\\Programs\\Python\\Python38\\lib\\site-packages\\_pytest\\python.py'>>] kwargs = {'pyfuncitem': <Function test_01>}, firstresult = True def _hookexec(self, hook_name, methods, kwargs, firstresult): # called from all hookcaller instances. # enable_tracing will set its own wrapping function at self._inner_hookexec > return self._inner_hookexec(hook_name, methods, kwargs, firstresult) ..\..\..\..\AppData\Local\Programs\Python\Python38\lib\site-packages\pluggy\_manager.py:80: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ hook_name = 'pytest_pyfunc_call' hook_impls = [<HookImpl plugin_name='python', plugin=<module '_pytest.python' from 'C:\\Users\\11130\\AppData\\Local\\Programs\\Python\\Python38\\lib\\site-packages\\_pytest\\python.py'>>] caller_kwargs = {'pyfuncitem': <Function test_01>}, firstresult = True def _multicall(hook_name, hook_impls, caller_kwargs, firstresult): """Execute a call into multiple python functions/methods and return the result(s). ``caller_kwargs`` comes from _HookCaller.__call__(). """ __tracebackhide__ = True results = [] excinfo = None try: # run impl and wrapper setup functions in a loop teardowns = [] try: for hook_impl in reversed(hook_impls): try: args = [caller_kwargs[argname] for argname in hook_impl.argnames] except KeyError: for argname in hook_impl.argnames: if argname not in caller_kwargs: raise HookCallError( f"hook call must provide argument {argname!r}" ) if hook_impl.hookwrapper: try: gen = hook_impl.function(*args) next(gen) # first yield teardowns.append(gen) except StopIteration: _raise_wrapfail(gen, "did not yield") else: res = hook_impl.function(*args) if res is not None: results.append(res) if firstresult: # halt further impl calls break except BaseException: excinfo = sys.exc_info() finally: if firstresult: # first result hooks return a single value outcome = _Result(results[0] if results else None, excinfo) else: outcome = _Result(results, excinfo) # run all wrapper post-yield blocks for gen in reversed(teardowns): try: gen.send(outcome) _raise_wrapfail(gen, "has second yield") except StopIteration: pass > return outcome.get_result() ..\..\..\..\AppData\Local\Programs\Python\Python38\lib\site-packages\pluggy\_callers.py:60: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <pluggy._result._Result object at 0x000001CE0142B430> def get_result(self): """Get the result(s) for this hook call. If the hook was marked as a ``firstresult`` only a single value will be returned otherwise a list of results. """ __tracebackhide__ = True if self._excinfo is None: return self._result else: ex = self._excinfo > raise ex[1].with_traceback(ex[2]) ..\..\..\..\AppData\Local\Programs\Python\Python38\lib\site-packages\pluggy\_result.py:60: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ hook_name = 'pytest_pyfunc_call' hook_impls = [<HookImpl plugin_name='python', plugin=<module '_pytest.python' from 'C:\\Users\\11130\\AppData\\Local\\Programs\\Python\\Python38\\lib\\site-packages\\_pytest\\python.py'>>] caller_kwargs = {'pyfuncitem': <Function test_01>}, firstresult = True def _multicall(hook_name, hook_impls, caller_kwargs, firstresult): """Execute a call into multiple python functions/methods and return the result(s). ``caller_kwargs`` comes from _HookCaller.__call__(). """ __tracebackhide__ = True results = [] excinfo = None try: # run impl and wrapper setup functions in a loop teardowns = [] try: for hook_impl in reversed(hook_impls): try: args = [caller_kwargs[argname] for argname in hook_impl.argnames] except KeyError: for argname in hook_impl.argnames: if argname not in caller_kwargs: raise HookCallError( f"hook call must provide argument {argname!r}" ) if hook_impl.hookwrapper: try: gen = hook_impl.function(*args) next(gen) # first yield teardowns.append(gen) except StopIteration: _raise_wrapfail(gen, "did not yield") else: > res = hook_impl.function(*args) ..\..\..\..\AppData\Local\Programs\Python\Python38\lib\site-packages\pluggy\_callers.py:39: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ pyfuncitem = <Function test_01> @hookimpl(trylast=True) def pytest_pyfunc_call(pyfuncitem: "Function") -> Optional[object]: testfunction = pyfuncitem.obj if is_async_function(testfunction): async_warn_and_skip(pyfuncitem.nodeid) funcargs = pyfuncitem.funcargs testargs = {arg: funcargs[arg] for arg in pyfuncitem._fixtureinfo.argnames} > result = testfunction(**testargs) ..\..\..\..\AppData\Local\Programs\Python\Python38\lib\site-packages\_pytest\python.py:183: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ def test_01(): a = 1 > assert a == 2 E assert 1 == 2 test_traceback.py:5: AssertionError =========================== short test summary info =========================== FAILED test_traceback.py::test_01 - assert 1 == 2 ============================== 1 failed in 0.35s ==============================
本文来自博客园,作者:他还在坚持嘛,转载请注明原文链接:他还在坚持嘛 https://www.cnblogs.com/brf-test/p/15730098.html