pytest 重构

54 阅读7分钟

pytest获取命令行参数

[www.cnblogs.com/qican/p/176…]
使用pytest_addoption

def pytest_addoption(parser):
    parser.addoption(
        "--anjing", action="store", default="anjing", help="将'anjing'添加到pytest的配置参数中"
    )

@pytest.fixture()
def anjing(request):
    return request.config.getoption("--anjing")

fixture调用其他fixture

fixture 具有不同的作用域(scope),如 functionclassmodulesession。 具有更小作用域的 fixture 可以调用具有更大作用域的 fixture,但反之则不行。

fixture调用fixture时,被调用的fixture先被调用,执行的结果赋值给被调用fixture的同名参数,该参数作为fixture参数进行后续操作。

fixture调用fixture只能用传参的方式,不能使用@pytest.mark.usefixtures()方式。

fixture 加载顺序

[blog.csdn.net/weixin_4597…]
(1)范围大的先执行
(2)同一范围的,autouse先执行
(3)被调用的fixture,先于要执行的fixture执行

test函数调用其他fixture

调用方式

blog.csdn.net/IT_heima/ar… (1)把fixture当做参数调用

(2)使用usefixture
2.1 适用于无返回值的fixture。或者yield方式的setup/teardown.

@pytest.mark.usefixtures("cleandir")

2.2 多个usefixture调用顺序
多个fixture叠加。先执行底层的,然后执行上层的。比如下面这个,先执行fixture2,再执行fixture1

@pytest.mark.usefixtures("fixture1")
@pytest.mark.usefixtures("fixture2")
def test_a():
    return

(3) fixture使用autouse参数

注册标签

运行对应标签的用例,先注册标签。 (1)pytest.ini

[pytest]
markers=
    aaa:mao yan
    bbb
    ccc
    ddd

# 标签名冒号后面可以添加注释信息必须是英文
# 红色字段为固定模式,不能改变   

(2) conftest.py文件注册

def pytest_configure(config):
    config.addinivalue_line("markers", "smoke1:标记只运行冒烟用例")
    config.addinivalue_line("markers", "demo1:示例运行")

test打用例标签

www.cnblogs.com/xiaogongjin… (1)在测试用例/测试类前加上:@pytest.mark.标记名

@pytest.mark.smoke
def test_add_01():
    b = 1 + 2
    assert 3 == b

(2)也可以在一个用例上打多个标签,多次使用@pytest.mark.标签名

@pytest.mark.demo
@pytest.mark.smoke
def test_add_02():
    b = 1 + 2
    assert 0 == b

(3)在测试类里面,使用以下声明(测试类下,所有用例都被打上了该标签)

@pytest.mark.smoke
class TestAdd:

    pytestmark = pytest.mark.smoke

    def test_add_03(self):
        b = 1 + 2
        print(f'b={b}')
        assert 3 == b

(4)类的多标签模式:pytestmark = [pytest.mark.标签1, pytest.mark.标签2......]

class TestAdd:

    pytestmark = [pytest.mark.smoke, pytest.mark.demo]

    def test_add_03(self):
        b = 1 + 2
        print(f'b={b}')
        assert 3 == b

(5)在模块文件里,同理(py文件下,所有测试函数和测试类里的测试函数,都有该标签)

import pytest
pytestmark = pytest.mark.smoke
pytestmark = [pytest.mark.smoke, pytest.mark.demo]  # 多标签模式

运行标签用例

# 执行被标记为smoke的用例 
pytest -m smoke 

# 执行被标记为smoke且被标记为login的用例 
pytest -m "smoke and login" 

# 执行被标记为smoke或login的用例 
pytest -m "smoke or login"

设置setup teardown

www.cnblogs.com/Nephalem-26…
(1)yield方式
yield前面可看为前置步骤,yield后面为后置步骤。这个方法的缺点是,yield前报错,yield后的代码不执行。但是如果test代码报错,yield之后的代码依然会执行。

import pytest
  
@pytest.fixture(scope="session")
def login():
    print("输入账号密码")
    yield
    print("清理数据完成")

(2)addfinalizer
addfinalizer是栈结构,添加的注册函数,先添加的后执行

@pytest.fixture()
def demo_fixture(request):
    print("\n这个fixture在每个case前执行一次")
 
    def demo_finalizer():
        print("\n在每个case完成后执行的teardown")
 
    def demo_finalizer2():
        print("\n在每个case完成后执行的teardown2")
 
    def demo_finalizer3():
        print("\n在每个case完成后执行的teardown3")
 
    # 注册demo_finalizer为终结函数
    request.addfinalizer(demo_finalizer)
    request.addfinalizer(demo_finalizer2)
    request.addfinalizer(demo_finalizer3)

def test_01(demo_fixture):
    print("\n===执行了case: test_01===")
===执行了case: test_01===
 
在每个case完成后执行的teardown3
 
在每个case完成后执行的teardown2
 
在每个case完成后执行的teardown

(3)xunit-style set-up
docs.pytest.org/en/stable/h…

  • It is possible for setup/teardown pairs to be invoked multiple times per testing process.
  • teardown functions are not called if the corresponding setup function existed and failed/was skipped.
  • setup_function 不会作用在 class内的函数

3.1 module level

def setup_module():
    """setup any state specific to the execution of the given module."""


def teardown_module():
    """teardown any state that was previously setup with a setup_module
    method.
    """

3.2 class level

@classmethod
def setup_class(cls):
    """setup any state specific to the execution of the given class (which
    usually contains tests).
    """


@classmethod
def teardown_class(cls):
    """teardown any state that was previously setup with a call to
    setup_class.
    """

3.3 Method and function level

def setup_method(self):
    """setup any state tied to the execution of the given method in a
    class.  setup_method is invoked for every test method of a class.
    """


def teardown_method(self):
    """teardown any state that was previously setup with a setup_method
    call.
    """
def setup_function():
    """setup any state tied to the execution of the given function.
    Invoked for every test function in the module.
    """


def teardown_function():
    """teardown any state that was previously setup with a setup_function
    call.
    """

debug调试

进入失败用例

pytest --pdb

执行用例时进入test

pytest --trace

?如何调试fixture

pytest生成报告

pip install pytest-html
pytest --html=report.html

总结fixture特点和用途

pytest命名参数

wangxiaoxi.cn/posts/pytho…

-s: 输出调试信息,包括print
-v: 运行时输出更详细的用例执行信息 不使用 -v 参数,运行时不会显示运行的具体测试用例名称;使用 -v 参数,会在 console 里打印出具体哪条测试用例被运行。
-m: 用表达式指定多个标记名。
-q: 用来简化运行输出信息.
-k: 可以通过表达式运行指定的测试用例。 它是一种模糊匹配,用 andor 区分各个关键字,匹配范围有文件名、类名、函数名。
-x: 出现一条测试用例失败就退出测试。 在调试时,这个功能非常有用。当出现测试失败时,停止运行后续的测试。

pytest执行用例

wangxiaoxi.cn/posts/pytho…
pytest 里选择测试用例执行有很多方法,可以按照测试文件夹、测试文件、测试类和测试方法四种。

  • 按照测试文件夹执行

    # 执行所有当前文件夹及子文件夹下的所有测试用例   
    pytest .   
    # 执行跟当前文件夹同级的tests文件夹及子文件夹下的所有测试用例  
    pytest ../tests
    
  • 按照测试文件执行

    # 运行test_se.py下的所有的测试用例
    pytest test_se.py
    
  • 按照测试类执行

    #按照测试类执行,必须以如下格式:
    pytest 文件名.py::测试类,其中“::”是分隔符,用于分割测试module和测试类。 
    # 运行test_se.py文件下的,类名是TestSE下的所有测试用例
    pytest test_se.py::TestSE
    
  • 按照测试方法执行

    # 同样的测试方法执行,必须以如下格式:
    pytest 文件名.py::测试类::测试方法,其中 “::” 是分隔符,用于分割测试module、测试类,以及测试方法。
    # 运行test_se.py文件下的,类名是TestSE下的,名字为test_get_new_message的测试用例 
    pytest test_se.py::TestSE::test_get_new_message
    

    以上选择测试用例执行的方法,可以不在命令行,而直接在测试程序里执行,其语法为

    pytest.main([模块.py::类::方法])
    
  • 按mark执行

    # 同时选中带有这两个标签的所有测试用例运行
    pytest -m "mark1 and mark2"
    # 选中带有mark1的测试用例,不运行mark2的测试用例
    pytest -m "mark1 and not mark2"
    # 选中带有mark1或 mark2标签的所有测试用例
    pytest -m "mark1 or mark2"
    
  • 关键词匹配
    pytest中,动态挑选测试用例,除了打标签(mark)外,还有另外一种方式:按照文件名、类名、方法名来模糊匹配的

    # -k 参数是按照文件名、类名、方法名来模糊匹配的
    pytest -k xxxPattern
    
    -   按照文件名称全匹配:
    # 运行test_se.py下的所有的测试
    pytest -k "test_se.py"
        
    -   按照文件名字部分匹配:
    # 因为se能匹配上test_se.py,故运行test_se.py下所有的测试
    pytest -k "se"
    
    -   按照类名匹配:
    # 因为Baidu能匹配上test_baidu.py里定义的测试类Baidu,故运行Baidu测试类下所有的测试,你也可以写成Bai.
    pytest -k "Baidu"
    
    -   按照方法名匹配:
    # message只能匹配test_se.py中定义的测试类TestSE下的测试方法test_get_new_message,故仅有test_get_new_message这个方法会执行
    pytest -k "message"
    
  • 多进程运行case

    pytest test_se.py -n NUM 
    # 其中NUM填写并发的进程数 
    # 需要安装pytest-xdist
    
  • 重跑失败用例

    pytest test_se.py --reruns NUM --reruns-delay m
    # 其中NUM填写重试的次数
    # m填写等待运行秒数
    # 需要安装pytest-rerunfailures