将参数传递给pytest固定装置进行拆卸

时间:2019-10-24 22:00:08

标签: pytest fixtures

问题: 清理从测试创建的测试工件。在以下情况下,如何使用pytest固定装置从数据库中删除测试期间创建的单行? (并非每次运行后都应从表中删除所有内容。否则,可以使用“删除所有行或删除表”)。在测试过程中,创建的行的行标识符将保存在一个函数变量中。

是否可以将在测试过程中创建的变量作为参数传递给pytest中的夹具?无论测试是通过失败还是成功完成,夹具都需要始终运行。在运行测试之前,不会知道行标识符。

用夹具说明问题

@pytest.fixture()
def clean_up_db_row(row_id):
    yield
    delete_from_db(self.row_id). # code to delete the row based on the id


def test_something_added_to_database(clean_up_db_row):
    row_id = create_db_row()  # function under test
    ...
    assert row_id in db  # test that information added to the database

    # the clean_up_db_row fixture will always run but how will it know about the id variable defined in the function?

如果断言在测试中途失败,则在清理结束时不会删除测试期间添加的行。因为测试停止执行。

问题的示例是没有pytest固定装置:

def clean_up_db_row(row_id):
    yield
    delete_from_db(row_id). # code to delete the row based on the id


def test_something_added_to_database():
    row_id = create_db_row()  # function under test
    ...
    assert row_id in db  # test that information added to the database
    clean_up_db_row(row_id)  # this won’t run if there is a failure

没有pytest固定装置的解决方案


def clean_up_db_row(row_id):
    yield
    delete_from_db(row_id). # code to delete the row based on the id

def test_something_added_to_database():
    row_id = create_db_row()  # function under test
    ...
    try:
        assert row_id in db  # test that information added to the database
    except Exception as e:
        raise e
    finally:
        clean_up_db_row(row_id)  # this will always run but doesn’t use a fixture

在类上使用实例变量的潜在解决方案

class TestCaseCleanUp:

    @pytest.fixture(autouse=True)
    def clean_up_db_row(self):
        yield
        delete_from_db(self.row_id). # code to delete the row based on the id


    def test_something_added_to_database(self):
        self.row_id = create_db_row()  # function under test
        ...
        assert self.row_id in db  # test that information added to the database
        # the autouse fixture can use the self.row_id assigned

2 个答案:

答案 0 :(得分:2)

跑步者将夹具产生的对象注入到测试环境中。这可以是您想要的任何对象,并且测试可以随意对其进行突变。

以下是一种适合您的模式:

@pytest.fixture()
def clean_up_db_rows():
    row_ids = []
    yield row_ids
    for row_id in row_ids:
        delete_from_db(row_id)


def test_something_added_to_database(clean_up_db_rows):
    row_id = create_db_row()  # function under test
    clean_up_db_rows.append(row_id)
    ...
    assert row_id in db  # test that information added to the database

答案 1 :(得分:0)

我找到了另一个解决方案here

<块引用>

在 conftest.py 中创建一个类并将其导入到您的测试模块中。为了保护自己免受假设在类中添加值的失败测试用例导致的错误,请将 None 分配给所有已知值。

conftest.py:

class ValueStorage:
    value1 = None
    value2 = None

test_mytest.py:

from conftest import ValueStorage

def test_one():
    ValueStorage.value1 = "anything you want here"
def test_two():
    assert ValueStorage.value1 == "anything you want here"
    ValueStorage.value2 = ValueStorage.value1

class TestClass:
    def test_three(self):
        assert ValueStorage.value1 == ValueStorage.value2
<块引用>

您可以传递字典和列表以及您喜欢的任何内容。如果您需要持久性(希望将值从一次运行保存到另一次运行,您可以将它们写入 json 文件或使用缓存选项)