通过pytest重置Python中每个测试的类和类变量

2024-04-18 23:47:01 发布

您现在位置:Python中文网/ 问答频道 /正文

我创建了一个类,以便在进行涉及工人及其合同的集成测试时使我的生活更轻松。代码如下所示:

class ContractID(str):
    contract_counter = 0
    contract_list = list()

    def __new__(cls):
        cls.contract_counter += 1
        new_entry = super().__new__(cls, f'Some_internal_name-{cls.contract_counter:10d}')
        cls.contract_list.append(new_entry)
        return new_entry

    @classmethod
    def get_contract_no(cls, worker_number):
        return cls.contract_list[worker_number-1]  # -1 so WORKER1 has contract #1 and not #0 etc.

当我对类进行单元测试时,我使用以下代码:

from test_helpers import ContractID

@pytest.fixture
def get_contract_numbers():
    test_string_1 = ContractID()
    test_string_2 = ContractID()
    test_string_3 = ContractID()
    return test_string_1, test_string_2, test_string_3


def test_contract_id(get_contract_numbers):
    assert get_contract_ids[0] == 'Some_internal_name-0000000001'
    assert get_contract_ids[1] == 'Some_internal_name-0000000002'
    assert get_contract_ids[2] == 'Some_internal_name-0000000003'


def test_contract_id_get_contract_no(get_contract_numbers):
    assert ContractID.get_contract_no(1) == 'Some_internal_name-0000000001'
    assert ContractID.get_contract_no(2) == 'Some_internal_name-0000000002'
    assert ContractID.get_contract_no(3) == 'Some_internal_name-0000000003'
    with pytest.raises(IndexError) as py_e:
        ContractID.get_contract_no(4)
    assert py_e.type == IndexError

但是,当我尝试运行这些测试时,第二个测试(test_contract_id_get_contract_no)失败,因为它不会引发错误,因为有三个以上的值。此外,当我尝试运行文件夹test/中的所有测试时,即使第一个测试(test_contract_id)也会失败,这可能是因为我试图在测试之前运行的其他测试中使用此函数

在阅读了this book之后,我对fixture的理解是,它提供了对象,就好像它们以前从未被调用过一样,这显然不是这里的情况。有没有一种方法可以告诉测试使用这个类,就好像它以前在其他地方没有被使用过一样


Tags: nonametestidnewgetstringdef
1条回答
网友
1楼 · 发布于 2024-04-18 23:47:01

如果我理解正确,那么您希望将fixture作为设置代码运行,以便您的类正好有3个实例。如果fixture是函数范围的(默认),那么它确实会在每次测试之前运行,每次测试都会为类创建3个新实例。如果你想在测试后重置你的类,你必须自己做——pytest无法猜测你想在这里做什么

因此,一个有效的解决方案应该是这样的:

@pytest.fixture(autouse=True)
def get_contract_numbers():
    test_string_1 = ContractID()
    test_string_2 = ContractID()
    test_string_3 = ContractID()
    yield 
    ContractID.contract_counter = 0
    ContractID.contract_list.clear()

def test_contract_id():
    ...

请注意,我没有生成测试字符串,因为在显示的测试中不需要它们-如果需要它们,当然可以生成它们。我还添加了autouse=True,如果所有测试都需要它,这是有意义的,因此不必在每个测试中引用fixture

另一种可能是使用会话范围的固定装置。在这种情况下,设置将只执行一次。如果这是您所需要的,您可以使用此选项:

@pytest.fixture(autouse=True, scope="session")
def get_contract_numbers():
    test_string_1 = ContractID()
    test_string_2 = ContractID()
    test_string_3 = ContractID()
    yield 

相关问题 更多 >