跟着官方文档理解Fixture用法(三)

Fixture 报错机制:

pytest does its best to put all the fixtures for a given test in a linear order so that it can see which fixture happens first, second, third, and so on. If an earlier fixture has a problem, though, and raises an exception, pytest will stop executing fixtures for that test and mark the test as having an error

pytest在执行时将所有的fixture放在一个队列中,我们可以知道他们的先后执行顺序,当一个较早执行的fixture发生错误时,会抛出异常,pytest会停止执行后面的fixture并标记测试中有一个错误

When a test is marked as having an error, it doesn’t mean the test failed, though. It just means the test couldn’t even be attempted because one of the things it depends on had a problem.

当测试用例标记了错误时,并不是意味着测试失败了,只是说明测试用例的依赖输入【前提条件】中有问题

This is one reason why it’s a good idea to cut out as many unnecessary dependencies as possible for a given test. That way a problem in something unrelated isn’t causing us to have an incomplete picture of what may or may not have issues.

这就是为什么需要去掉那些不必要的依赖输入,这样的话,不相关的问题就不会导致我们对问题进行不完整的描述

import pytest

@pytest.fixture
def order():
    return []

@pytest.fixture
def append_first(order):
    order.append(1)

@pytest.fixture
def append_second(order, append_first):
    order.extend([2])

@pytest.fixture(autouse=True)
def append_third(order, append_second):
    order += [3]

def test_order(order):
    assert order == [1, 2, 3]

上面的例子中,当order.append(1)有bug,抛出异常,我们不会知道order.extend[2]或order += [3]是否也有问题。在append_first抛出异常后,pytest不会再继续执行test_order用例中后面剩余的fixture,也不会去运行test_order用例本身,仅仅执行了order和append_first

Fixture 结束化【teardown/cleanup清理垃圾数据】

当我们执行测试用例时,我们都希望在测试用例执行完成后,保证测试用例在系统中添加的数据被清理干净,不影响其他后续的测试用例。pytest提供了一个非常有用的teardown系统,允许我们给每个fixture定义特定的步骤去清理fixture自身产生的数据影响,有2种方式可以实现

方法1:yield【推荐使用】

import pytest

from emaillib import Email, MailAdminClient

@pytest.fixture
def mail_admin():
    return MailAdminClient()

@pytest.fixture
def sending_user(mail_admin):
    user = mail_admin.create_user()
    yield user
    admin_client.delete_user(user)

@pytest.fixture
def receiving_user(mail_admin):
    user = mail_admin.create_user()
    yield user
    admin_client.delete_user(user)

def test_email_received(receiving_user, email):
    email = Email(subject="Hey!", body="How's it going?")
    sending_user.send_email(_email, receiving_user)
    assert email in receiving_user.inbox

当fixture按照顺序执行完成后,执行teardown时,pytest会按照fixture执行顺序倒序执行teardown操作

当yield fixture在执行yield之前抛出错误时,pytest不会去尝试执行yield之后的teardown代码;但是,对于每个已经在该测试中成功运行的fixture,pytest仍然会像平时一样把他们销毁

方法2:直接添加teardown代码

import pytest

from emaillib import Email, MailAdminClient

@pytest.fixture
def mail_admin():
    return MailAdminClient()

@pytest.fixture
def sending_user(mail_admin):
    user = mail_admin.create_user()
    yield user
    admin_client.delete_user(user)

@pytest.fixture
def receiving_user(mail_admin, request):
    user = mail_admin.create_user()

    def delete_user():
        admin_client.delete_user(user)

    request.addfinalizer(delete_user)
    return user

@pytest.fixture
def email(sending_user, receiving_user, request):
    _email = Email(subject="Hey!", body="How's it going?")
    sending_user.send_email(_email, receiving_user)

    def empty_mailbox():
        receiving_user.delete_email(_email)

    request.addfinalizer(empty_mailbox)
    return _email

def test_email_received(receiving_user, email):
    assert email in receiving_user.inbox

conftest.py fixture的配置文件

conftest.py文件可以提供fixture在一个包内的多个文件中共用而不需要手动导入(pytest会自动查找当前包内是否有conftest.py,如果没有,则到上一级目录去寻找)

下面例子

tests/
    __init__.py

    conftest.py
        # content of tests/conftest.py
        import pytest

        @pytest.fixture
        def order():
            return []

        @pytest.fixture
        def top(order, innermost):
            order.append("top")

    test_top.py
        # content of tests/test_top.py
        import pytest

        @pytest.fixture
        def innermost(order):
            order.append("innermost top")

        def test_order(order, top):
            assert order == ["innermost top", "top"]

    subpackage/
        __init__.py

        conftest.py
            # content of tests/subpackage/conftest.py
            import pytest

            @pytest.fixture
            def mid(order):
                order.append("mid subpackage")

        test_subpackage.py
            # content of tests/subpackage/test_subpackage.py
            import pytest

            @pytest.fixture
            def innermost(order, mid):
                order.append("innermost subpackage")

            def test_order(order, top):
                assert order == ["mid subpackage", "innermost subpackage", "top"]

在上面的例子中,各个fixture和测试用例的关系如下图表示

posted @ 2021-04-28 14:07  Hei蛋炒饭  阅读(108)  评论(0编辑  收藏  举报