测试夹具是为了给测试脚本提供一个固定的基准。

可以理解为使测试脚本可以重复、可靠地调用这些夹具进行组装测试脚本。(如果有经典的xunit样式中的setup和teardown概念,可以看作是对这两个东西的进一步的封装,细化各个预置和清理步骤,方便更灵活的组装测试脚本构成)

  • 通过从测试方法,模块,类或整个项目中声明夹具,用夹具名称来使用测试夹具。
  • 夹具以模块化的方式实现,可以把每个夹具看作一个测试步骤, 夹具本身可以调用其他夹具。
  • 可以对夹具和测试进行参数化,或者在方法,类,模块或整个测试会话范围内重复使用夹具。

夹具作为函数参数

# content of ./test_fixture.py
import pytest


@pytest.fixture
def smtp_connection():
    import smtplib

    return smtplib.SMTP_SSL("smtp.qq.com", 465, timeout=5)


def test_ehlo(smtp_connection):
    response, msg = smtp_connection.ehlo()
    assert response == 250

执行过程

  1. 因为test_前缀符合pytest收集测试程序的规范,所以pytest执行test_ehlo测试;
  2. 测试函数需要一个smtp_connection参数,用该参数匹配查找同名测试夹具;
  3. 找到后实例化该参数,被测试程序调用;

夹具:依赖注入

夹具共享:conftest.py

如果在编写测试时发现要使用多个测试文件中的夹具,可以将它们打包放到目录下的conftest.py文件中。

  1. 不需要导入要在测试中使用的夹具,它会被pytest自动发现。

  2. 发现顺序: 测试类 -> 模块 -> conftest.py -> 内置插件 -> 第三方插件

  3. 作用范围 scope

    • function
    • class 在每个测试类中调用一次夹具
    • module
    • package
    • session
  4. 调用顺序

夹具:setup和teardown功能

# content of ./test_fixture.py
import smtplib
import pytest


@pytest.fixture(scope="module")
def smtp_connection(request):
    smtp_connection = smtplib.SMTP_SSL("smtp.qq.com", 465, timeout=5)

    def fin():
        print("teardown smtp_connection")
        smtp_connection.close()

    request.addfinalizer(fin)
    return smtp_connection


def test_ehlo(smtp_connection):
    response, msg = smtp_connection.ehlo()
    assert response == 250

夹具工厂模式

# content of ./test_fixture.py
import random
import pytest


@pytest.fixture
def make_customer_record():
    created_records = []

    def _make_customer_record(name):
        record = random.choice(name)
        created_records.append(record)
        return record

    yield _make_customer_record
    created_records.clear()


def test_customer_records(make_customer_record):
    make_customer_record("Lisa")
    make_customer_record("Mike")
    make_customer_record("Meredith")

夹具的嵌套和参数化

# content of ./test_fixture.py
import pytest
import smtplib


@pytest.fixture(scope="module", params=["smtp.qq.com", "mail.python.org"])
def smtp_connection(request):
    smtp_connection = smtplib.SMTP_SSL(request.param, 465, timeout=5)
    yield smtp_connection
    print("finalizing {}".format(smtp_connection))
    smtp_connection.close()


class App:
    def __init__(self, smtp_connection):
        self.smtp_connection = smtp_connection


@pytest.fixture(scope="module")
def app(smtp_connection):
    return App(smtp_connection)


def test_smtp_connection_exists(app):
    assert app.smtp_connection

自动使用夹具

@pytest.fixture(autouse=True)

夹具覆盖

  1. 文件夹级别子目录覆盖父级目录同名测试夹具;
02-08 03:12