pytest fixture-拆除fixture

2022-03-18 14:10 更新

在我們運(yùn)行測(cè)試時(shí),我們希望確保它們?cè)谧约和瓿芍筮M(jìn)行清理,這樣它們就不會(huì)擾亂其他測(cè)試(也不會(huì)留下大量的測(cè)試數(shù)據(jù)來膨脹系統(tǒng))。pytest中的??fixture??提供了一個(gè)非常有用的拆卸系統(tǒng),它允許我們?yōu)槊總€(gè)??fixture??定義必要的特定步驟,以便在它們自己之后進(jìn)行清理。

該系統(tǒng)可以利用在兩個(gè)方面。

1、yield fixtures

使用這些??fixture??,我們可以運(yùn)行一些代碼并將一個(gè)對(duì)象傳回請(qǐng)求??fixture/test??,就像使用其他??fixture??一樣。唯一的區(qū)別是:

  • ??return??被換成了??yield??。
  • 該??fixture??的拆卸代碼位于生成之后。

一旦pytest為??fixture??確定了一個(gè)線性順序,它將運(yùn)行每個(gè)??fixture??,直到它返回或產(chǎn)生,然后移動(dòng)到列表中的下一個(gè)??fixture??來做同樣的事情。

測(cè)試完成后,pytest將返回??fixture??列表,但順序相反,獲取每個(gè)產(chǎn)生的??fixture??,并在其中運(yùn)行??yield??語句之后的代碼。

作為一個(gè)簡(jiǎn)單的例子,考慮這個(gè)基本的電子郵件模塊:

# content of emaillib.py
class MailAdminClient:
    def create_user(self):
        return MailUser()

    def delete_user(self, user):
        # do some cleanup
        pass


class MailUser:
    def __init__(self):
        self.inbox = []

    def send_email(self, email, other):
        other.inbox.append(email)

    def clear_mailbox(self):
        self.inbox.clear()


class Email:
    def __init__(self, subject, body):
        self.subject = subject
        self.body = body

假設(shè)我們想測(cè)試從一個(gè)用戶向另一個(gè)用戶發(fā)送電子郵件。我們必須首先創(chuàng)建每個(gè)用戶,然后從一個(gè)用戶向另一個(gè)用戶發(fā)送電子郵件,最后斷言另一個(gè)用戶在他們的收件箱中收到了這條消息。如果我們想在測(cè)試運(yùn)行后進(jìn)行清理,我們必須確保在刪除其他用戶之前清空該用戶的郵箱,否則系統(tǒng)可能會(huì)報(bào)錯(cuò)。

這可能是這樣的:

# content of test_emaillib.py
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
    mail_admin.delete_user(user)


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


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

因?yàn)??receiving_user??是安裝期間運(yùn)行的最后一個(gè)??fixture??,所以它是拆卸期間運(yùn)行的第一個(gè)??fixture??。

$ pytest -q test_emaillib.py
.                                                                    [100%]
1 passed in 0.12s

處理yield fixture的錯(cuò)誤

如果??yield fixture??在??yield??之前引發(fā)異常,pytest將不會(huì)嘗試在該??yield fixture??的??yield??語句之后運(yùn)行拆卸代碼。但是,對(duì)于已經(jīng)為該測(cè)試成功運(yùn)行的每個(gè)??fixture??, pytest仍然會(huì)像正常情況一樣試圖將它們刪除。

2、直接添加finalizers

雖然??yield fixture??被認(rèn)為是更干凈和更直接的選項(xiàng),但還有另一種選擇,即直接向測(cè)試的請(qǐng)求上下文對(duì)象添加??finalizer??函數(shù)。它帶來了與??yield fixture??類似的結(jié)果,但需要更多的細(xì)節(jié)。為了使用這種方法,我們必須在需要添加??teardown??代碼的??fixture??中請(qǐng)求請(qǐng)求上下文對(duì)象(就像我們請(qǐng)求另一個(gè)??fixture??一樣),然后將包含該??teardown??代碼的可調(diào)用對(duì)象傳遞給它的??addfinalizer??方法。但是,我們必須小心,因?yàn)閜ytest將在添加??finalizer??后運(yùn)行該??finalizer??,即使該??fixture??在添加??finalizer??后引發(fā)異常。因此,為了確保我們不會(huì)在不需要的時(shí)候運(yùn)行??finalizer??代碼,我們只會(huì)在??fixture??做了一些我們需要拆除的事情時(shí)添加??finalizer??。下面是使用??addfinalizer??方法的前一個(gè)例子:

# content of test_emaillib.py
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
    mail_admin.delete_user(user)


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

    def delete_user():
        mail_admin.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.clear_mailbox()

    request.addfinalizer(empty_mailbox)
    return _email


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

它比??yield fixture??要長(zhǎng)一點(diǎn),也更復(fù)雜一點(diǎn),但當(dāng)你在緊要關(guān)頭時(shí),它確實(shí)提供了一些細(xì)微的差別。

$ pytest -q test_emaillib.py
.                                                                    [100%]
1 passed in 0.12s


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)