【超详细】Pytest全栈自动化测试指南-夹具入门,让你快速提高测试效率!

二、夹具

2.1 什么是fixtures

在测试中,fixture为测试 提供了一个定义好的、可靠的和一致的上下文。这可能包括环境(例如配置有已知参数的数据库)或内容(例如数据集)。

2.2 使用上的理解

  1. 它是一个高级装饰器,通过被@Fixture标记的的函数,都叫做夹具.
  2. 把使用@Fixture标记的函数名称,传到任意用例的参数列表里面,即可使用
  3. 在不修改用例函数内部代码的前提下,扩展其功能,可以给用例提供数据,增强功能, 和测试前,测试后环境的初始化和清理工作。

2.3 初始化和清理

  • fixture 函数会在测试函数之前运行
  • 如fixtrue 函数包含yield,那么代码会在yield 处停止,转而运行测试函数,
  • 等测试函数执行完毕后,在回到fixtrue,继续执行yield 后面的代码。
  • 可以将yield 前、当做setup,yield后,当做teardown
  • 无论测试过程中发生了什么,yield后面的代码都会被执行。它的作用视为代码清理功能。
  • 类似UnitTest 里面的setup 和teardwn

2.4 共享夹具

  • conftest.py: 跨多个文件共享夹具
  • 该文件用作为整个目录提供共享Fixtrue 的一种方式,可以跨多个文件共享夹具,并且在用例模块中无需导入它们,pytest 会自动会发现conftest.py 中的夹具。
  • 您可以拥有多个包含测试的嵌套目录/包,并且每个目录都可以拥有conftest.py. 如果夹具出现重名,子级会覆盖父级中的夹具
  • conftest.py ,只针对当前目录和子级目录有效,对它当前的父级目录,不起作用。

2.5 代码案例

2.5.1 fixtrue夹具入门案例

# ---------------------------------conftest.py------------------------------------
import pytest

@pytest.fixture
def some_data():
    return 66


@pytest.fixture
def student_score():
    return {'小明': 99, '小红': 100}


@pytest.fixture
def student_name():
    return ['小明', '小红']


# ---------------------------------test_01_fixtures.py----------------------------
from pytest_assume.plugin import assume


def test_some(some_data):
    assert some_data == 66


def test_student(student_score, student_name):

    with assume:  # 实际的数据长度是否跟预期长度相同
        assert len(student_score) == 2, \
            f"实际数据长度:{len(student_score)} 与预期数据长度:{2}不相同!!"


    with assume:  # 预期数据是否在实际数据内
        assert '小红' in student_name, \
            f"预期数据:{'小红'}没在实际数据中:{student_name}!!"

2.5.2 完整邮件案例

测试步骤:

  • step1: 创建发邮件用户

    setp2: 创建收邮件用户

    step3:编写收发邮件功能用例。验证发件人可以正常发邮件到收件人邮箱里的功能用例。

    step4: 删除收件用户

    step5: 删 除发件用户

    说明:step1、step2 为提供资源,由夹具来实现、step4、step5为清理,由夹具实现。

# ---------------------------------mail.py----------------------------------------

from dataclasses import dataclass, field
from typing import List


class MailAdminClient: # 邮件管理后台

    def create_user(self): # 创建用户
        return MailUser()

    def delete_user(self, user): # 删除用户,未完成
        # do some cleanup
        pass


@dataclass
class Email:
    subject: str # 邮件主题
    body: str # 邮件内容


# 邮件使用人
@dataclass
class MailUser:
    # 收件箱
    inbox: List[Email] = field(default_factory=list)

    def send_email(self, email, other):
        """发送邮件
        :param email: 邮件(包括主题、内容)
        :param other: 收件人
        :return: None
        """
        other.inbox.append(email)

    def clear_mailbox(self):
        """清空邮箱
        :return:None
        """
        self.inbox.clear()


# ---------------------------------conftest.py------------------------------------
@pytest.fixture
def mail_admin():
    from btest.Day3.mail import MailAdminClient
    return MailAdminClient()


@pytest.fixture
def sending_user(mail_admin):

    user = mail_admin.create_user()
    print('\n--sending_user创建发送用户-------\n')

    yield user

    print('\n--sending_user删除发送用户-------\n')
    mail_admin.delete_user(user)


@pytest.fixture
def receiving_user(mail_admin):
    user = mail_admin.create_user()
    print('\n--receiving_user创建接受用户-------\n')

    yield user

    print('\n--receiving_user删除接受用户-------\n')
    mail_admin.delete_user(user)


# ---------------------------------test_02_email.py------------------------------
from btest.Day3.mail import Email


# step1:执行sending_user 创建发件用户
# step2: 执行receiving_user 创建收件用户
# step3: 执行test_email_received 用例
# step4: 执行receiving_user删除接受用户
# step5: 执行sending_user删除发送用户


def test_email_received(sending_user, receiving_user):
    print('\n--test_email_received执行测试-------\n')
    # 构造邮件
    email = Email(subject="Hey!", body="How's it going?")
    # 发送者发送邮件给接受者
    sending_user.send_email(email, receiving_user)

    # 断言 邮件是否在接收人的邮箱中
    assert email in receiving_user.inbox

# 说明:
# 同级别的夹具环境初始化是顺序、环境清理是逆序。
# 夹具yield 前面代码是按照参数顺序执行。环境初始化是顺序。
# 夹具yield 后面代码是按照参数逆序执行。环境清理是逆序。

2.5.3 夹具执行顺序

当 pytest 想要执行测试时,一旦它知道将执行哪些夹具,它就必须弄清楚它们将执行的顺序。为此,它考虑了 3 个因素:

  1. 范围 :首先执行更高范围的夹具 ,例如:顺序 session > package > moudle > class > method 。
    说明: 不管夹具在用例参数列表中,如何排列,都想先执行更高范围夹具
  2. 依赖关系 : 同级别夹具,当一个夹具请求另一个夹具时,首先执行另一个夹具。
  3. 自动夹具 : 同级别,在非自动夹具前执行。
    说明:标注为autouse=True的夹具,在同级别夹具中,
import pytest


@pytest.fixture(scope="session")
def order():
    return []


@pytest.fixture
def func_A(order):
    order.append("function_A")


@pytest.fixture
def func_B(func_A, order):
    order.append("function_B")


@pytest.fixture(autouse=True)  # 同级别自动夹具,最先执行。
def func_C(order):
    order.append("function_C")


@pytest.fixture(scope="class")
def cls(order):
    order.append("class")


@pytest.fixture(scope="module")
def mod(order):
    order.append("module")


@pytest.fixture(scope="package")
def pack(order):
    order.append("package")


@pytest.fixture(scope="session")
def sess(order):
    order.append("session")


class TestClass:
    def test_order(self, func_B, func_A, cls, mod, pack, sess, order):
        assert order == ['session', 'package', 'module', 'class', 'function_C', 'function_A', 'function_B']



2.5.4 夹具综合案例

# ----------------------------test_01_xh.py----------------------------------
# ----------------------------test_02_xm.py----------------------------------

# step1  夹具(session-自动) :初始化测试环境 与清理测环境。

# step2  夹具(module-自动):  登陆与退出

# step3  夹具(function) : 函数级别提供输入信息 和 结束输入信息。

# step4  用例(2个模块(4个)用例) : 用例1学生查询成绩,用例2学生修改成绩


# 注意:自动化夹具的使用场景,用例跟夹具,没有数据上的依赖时,可以使用自动化夹具。

    
 # 通过关键字表达式进行测试,执行用例名字中包含searh和edit的用例
 # pytest.main(['-qs', '-k', 'search or edit', '.\\Day4\\'])

>>>>>>>>>>>>session:测试开始-环境初始化<<<<<<<<<<<<<<<<

--------module:btest.Day4.test_01_xh:登陆成功-------
***function:test_xh_search:开始输入信息***
小红查询成绩
.***function:test_xh_search:结束输入信息***

***function:test_xh_edit:开始输入信息***
小红修改成绩
.***function:test_xh_edit:结束输入信息***
--------module:btest.Day4.test_01_xh:退出成功-------


--------module:btest.Day4.test_02_xm:登陆成功-------
***function:test_xm_search:开始输入信息***
小明查询成绩
.***function:test_xm_search:结束输入信息***

***function:test_xm_edit:开始输入信息***
小明修改成绩
.***function:test_xm_edit:结束输入信息***
--------module:btest.Day4.test_02_xm:退出成功-------


>>>>>>>>>>>>session:测试完毕-环境清理<<<<<<<<<<<<<<<<<<
# ----------------------------test_03_student.py----------------------------------

# step1  夹具(session-自动) :初始化测试环境 与清理测环境。

# step2  夹具(module-自动):  登陆与退出。

# step3  夹具(class-手动) : 类级别提供:  输入学生信息 和清空学生信息。

# step4  夹具(function-自动) : 函数级别提供:  开始输入信息 和 结束输入信息。

# step5  用例(2个class) : 用例1(判断小红是否在学成成绩表中),用例2(判断小明是否大于90分)

    
# 通过关键字表达式进行测试,执行用例名字中包含student的用例
# pytest.main(['-qs', '-k', 'student', '.\\Day4\\'])

>>>>>>>>>>>>session:测试开始-环境初始化<<<<<<<<<<<<<<<<

--------module:btest.Day4.test_03_student:登陆成功-------
+++class:TestStudentName:输入学生信息+++
***function:test_name:开始输入信息***
.***function:test_name:结束输入信息***
+++class:TestStudentName:清空学生信息+++

+++class:TestStudentScore:输入学生信息+++
***function:test_score:开始输入信息***
.***function:test_score:结束输入信息***
+++class:TestStudentScore:清空学生信息+++

--------module:btest.Day4.test_03_student:退出成功-------


>>>>>>>>>>>>session:测试完毕-环境清理<<<<<<<<<<<<<<<<<<

夹具常用场景总结

  1. session 级别夹具:整个测试用例中开头和结尾只运行一次或全局共享资源(全局参数关联)

  2. module级别夹具 :每个模块都需要重新初始化和运行,或在一个模块中共享某个资源(模块内部参数关联)

  3. class级别夹具: 每个class都需要重新初始化和运行, 在一个类中共享某个资源(某个类中参数关联)

  4. function级别夹具:每个用例都需要重新初始化和运行,用例之间不共享资源(不进行参数关联)

更多案例,更多内容,请点击: https://edu.csdn.net/course/detail/37237

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

百里图书

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值