pytest fixture-請(qǐng)求fixture

2022-03-23 14:33 更新

什么是fixture

在測(cè)試中,?fixture?為測(cè)試 提供了一個(gè)定義好的、可靠的和一致的上下文。這可能包括環(huán)境(例如配置有已知參數(shù)的數(shù)據(jù)庫)或內(nèi)容(例如數(shù)據(jù)集)。
?Fixtures ?定義了構(gòu)成測(cè)試排列階段的步驟和數(shù)據(jù)。在 pytest 中,它們是您定義的用于此目的的函數(shù)。它們也可以用來定義測(cè)試的行為階段;這是設(shè)計(jì)更復(fù)雜測(cè)試的強(qiáng)大技術(shù)。
由?fixture?設(shè)置的服務(wù)、狀態(tài)或其他操作環(huán)境由測(cè)試函數(shù)通過參數(shù)訪問。對(duì)于測(cè)試函數(shù)使用的每個(gè)?fixture?,在測(cè)試函數(shù)的定義中通常都有一個(gè)參數(shù)(以?fixture?命名)

在基本級(jí)別上,測(cè)試函數(shù)通過將??fixture??聲明為參數(shù)來請(qǐng)求它們所需要的??fixture??。

當(dāng)pytest運(yùn)行一個(gè)測(cè)試時(shí),它會(huì)查看該測(cè)試函數(shù)簽名中的參數(shù),然后搜索與這些參數(shù)具有相同名稱的??fixture??。一旦pytest找到它們,它就運(yùn)行這些??fixture??,捕獲它們返回的內(nèi)容(如果有的話),并將這些對(duì)象作為參數(shù)傳遞給測(cè)試函數(shù)。

快速示例

import pytest


class Fruit:
    def __init__(self, name):
        self.name = name
        self.cubed = False

    def cube(self):
        self.cubed = True


class FruitSalad:
    def __init__(self, *fruit_bowl):
        self.fruit = fruit_bowl
        self._cube_fruit()

    def _cube_fruit(self):
        for fruit in self.fruit:
            fruit.cube()


# Arrange
@pytest.fixture
def fruit_bowl():
    return [Fruit("apple"), Fruit("banana")]


def test_fruit_salad(fruit_bowl):
    # Act
    fruit_salad = FruitSalad(*fruit_bowl)

    # Assert
    assert all(fruit.cubed for fruit in fruit_salad.fruit)

在這個(gè)例子中,??test_fruit_salad??請(qǐng)求??fruit_bowl??(即??def test_fruit_salad(fruit_bowl):??),當(dāng)pytest看到這個(gè)時(shí),它將執(zhí)行??fruit_bowl fixture??函數(shù),并將它返回的對(duì)象作為??fruit_bowl??參數(shù)傳遞給??test_fruit_salad??

如果我們手動(dòng)進(jìn)行,大致會(huì)發(fā)生以下情況:

def fruit_bowl():
    return [Fruit("apple"), Fruit("banana")]


def test_fruit_salad(fruit_bowl):
    # Act
    fruit_salad = FruitSalad(*fruit_bowl)

    # Assert
    assert all(fruit.cubed for fruit in fruit_salad.fruit)


# Arrange
bowl = fruit_bowl()
test_fruit_salad(fruit_bowl=bowl)

Fixtures可以請(qǐng)求其他fixtures

pytest最大的優(yōu)勢(shì)之一是它極其靈活的??fixture??系統(tǒng)。它允許我們將測(cè)試的復(fù)雜需求歸結(jié)為更簡(jiǎn)單和更有組織的功能,我們只需要讓每個(gè)功能描述它們所依賴的東西。我們將進(jìn)一步深入討論這個(gè)問題,但現(xiàn)在,這里有一個(gè)快速的例子來演示??fixtures??如何使用其他??fixtures??:

# contents of test_append.py
import pytest


# Arrange
@pytest.fixture
def first_entry():
    return "a"


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


def test_string(order):
    # Act
    order.append("b")

    # Assert
    assert order == ["a", "b"]

請(qǐng)注意,這與上面的示例相同,但變化很小。 pytest 中的??fixture?請(qǐng)求??fixture ?就像測(cè)試一樣。 所有相同的請(qǐng)求規(guī)則都適用于用于測(cè)試的??fixture??。 如果我們手動(dòng)完成,這個(gè)例子的工作方式如下:

def first_entry():
    return "a"


def order(first_entry):
    return [first_entry]


def test_string(order):
    # Act
    order.append("b")

    # Assert
    assert order == ["a", "b"]


entry = first_entry()
the_list = order(first_entry=entry)
test_string(order=the_list)

Fixtures可重復(fù)使用

使pytest的??fixture??系統(tǒng)如此強(qiáng)大的原因之一是,它使我們能夠定義一個(gè)通用的設(shè)置步驟,這個(gè)步驟可以重復(fù)使用,就像使用一個(gè)普通函數(shù)一樣。兩個(gè)不同的測(cè)試可以請(qǐng)求相同的??fixture??,并讓pytest從該??fixture??為每個(gè)測(cè)試提供自己的結(jié)果。

這對(duì)于確保測(cè)試不會(huì)相互影響非常有用。 我們可以使用這個(gè)系統(tǒng)來確保每個(gè)測(cè)試都獲得自己的新一批數(shù)據(jù),并從干凈的狀態(tài)開始,這樣它就可以提供一致的、可重復(fù)的結(jié)果。

下面是一個(gè)例子,說明這是如何派上用場(chǎng)的:

# contents of test_append.py
import pytest


# Arrange
@pytest.fixture
def first_entry():
    return "a"


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


def test_string(order):
    # Act
    order.append("b")

    # Assert
    assert order == ["a", "b"]


def test_int(order):
    # Act
    order.append(2)

    # Assert
    assert order == ["a", 2]

這里的每個(gè)測(cè)試都有它自己的列表對(duì)象的副本,這意味著??order fixture??被執(zhí)行兩次(??first_entry fixture??也是如此)。如果我們手動(dòng)執(zhí)行,它看起來會(huì)是這樣的:

def first_entry():
    return "a"


def order(first_entry):
    return [first_entry]


def test_string(order):
    # Act
    order.append("b")

    # Assert
    assert order == ["a", "b"]


def test_int(order):
    # Act
    order.append(2)

    # Assert
    assert order == ["a", 2]


entry = first_entry()
the_list = order(first_entry=entry)
test_string(order=the_list)

entry = first_entry()
the_list = order(first_entry=entry)
test_int(order=the_list)

一個(gè)test/fixture一次可以請(qǐng)求多個(gè)fixture

測(cè)試和??fixture??不限于一次請(qǐng)求單個(gè)??fixture??。他們想要多少就可以要多少。下面是另一個(gè)快速演示的例子:

# contents of test_append.py
import pytest


# Arrange
@pytest.fixture
def first_entry():
    return "a"


# Arrange
@pytest.fixture
def second_entry():
    return 2


# Arrange
@pytest.fixture
def order(first_entry, second_entry):
    return [first_entry, second_entry]


# Arrange
@pytest.fixture
def expected_list():
    return ["a", 2, 3.0]


def test_string(order, expected_list):
    # Act
    order.append(3.0)

    # Assert
    assert order == expected_list

每個(gè)測(cè)試可以請(qǐng)求fixture多次(緩存返回值)

在同一測(cè)試期間,??fixture??也可以被請(qǐng)求多次,pytest不會(huì)為該測(cè)試再次執(zhí)行它們。這意味著我們可以請(qǐng)求多個(gè)依賴于它們的??fixture??(甚至在測(cè)試本身中的??fixture??),而不需要執(zhí)行多次這些??fixture??。

# contents of test_append.py
import pytest


# Arrange
@pytest.fixture
def first_entry():
    return "a"


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


# Act
@pytest.fixture
def append_first(order, first_entry):
    return order.append(first_entry)


def test_string_only(append_first, order, first_entry):
    # Assert
    assert order == [first_entry]

如果一個(gè)被請(qǐng)求的??fixture??在測(cè)試期間每次被請(qǐng)求時(shí)都被執(zhí)行一次,那么這個(gè)測(cè)試將會(huì)失敗,因?yàn)??append_first??和??test_string_only??都會(huì)將??order??視為一個(gè)空列表,但由于??order??的返回值在第一次被調(diào)用后被緩存(以及執(zhí)行它可能有的任何副作用),??test??和??append_first??都引用了同一個(gè)對(duì)象,測(cè)試中看到了??append_first??對(duì)該對(duì)象的影響。


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

掃描二維碼

下載編程獅App

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

編程獅公眾號(hào)