每天努力一点点,坚持下去 ------ 博客首页

Pytest进阶三阶段

Pytest相关

主流自动化测试框架设计体系

编程语言的选择:Python(80%)、java(20%)

 自动化模块:selenium/appium/requests

设计模式:关键字驱动/POM

-------------------------------------------初阶-----------------------------------------------

1、 关键字驱动

  1. 原始代码分离为:代码与数据
  2. 二次分离代码:行为代码与测试代码
  3. 数据驱动行为代码,生成:最终的基于关键字驱动的测试代码

作用:从而更加便捷的进行自动化测试代码的管理,以及提高自动化的复用性,让使用者更加容易理解和使用自动化。

  • 关键字驱动+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 数据驱动

  1. yaml 安装:pip install pyyaml
  2. yaml 是一种文件格式,可以在Pycharm中创建后缀为yaml的文件,类似于xml
  • yaml应用

  1. - ”: list(列表)标签
  2. ”: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:通过函数的形式将结果生成并返回

代码思路:

  1. yaml文件中编写三条数据

  2. 封装读取yaml的函数

  3. 使用@pytest.mark.parametrize()装饰器来调用数据

  4. 最终实现参数化调用执行

目录

 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
  1. 定时构建(自定义定时的执行自动化脚本)
  2. 任务触发构建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
安装要求:
  1. 需是python3.5-3.8或pypy3)
  2. 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 ==============================

 


 

posted @ 2021-12-25 22:10  他还在坚持嘛  阅读(325)  评论(0编辑  收藏  举报