Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/codeigniter/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
通过pytest重置Python中每个测试的类和类变量_Python_Python 3.x_Unit Testing_Pytest - Fatal编程技术网

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

通过pytest重置Python中每个测试的类和类变量,python,python-3.x,unit-testing,pytest,Python,Python 3.x,Unit Testing,Pytest,我创建了一个类,以便在进行涉及工人及其合同的集成测试时使我的生活更轻松。代码如下所示: 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.contrac

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

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.
@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():
    ...
当我对类进行单元测试时,我使用以下代码:

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\u contract\u id\u get\u contract\u no
)失败,因为它不会引发错误,因为有三个以上的值。此外,当我尝试运行文件夹
test/
中的所有测试时,即使第一个测试(
test\u contract\u id
)也会失败,这可能是因为我试图在测试之前运行的其他测试中使用此函数


在阅读之后,我对fixture的理解是,它提供的对象好像以前从未调用过一样,这里显然不是这样。有没有一种方法可以告诉测试如何使用该类,就好像它在其他任何地方都没有被使用过一样?

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

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

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.
@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
,如果您在所有测试中都需要它,这是有意义的,因此您不必在每个测试中引用夹具

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

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

我想可能有什么东西,可以让每个测试都从一张干净的石板开始,比如scope=“test”,它会忘记其他测试中的所有内容,并像以前没有运行任何测试一样运行测试。最后,我决定采用你的解决方案,放弃一切,然后清理一切。但是,我要指出的是,对于一些更复杂的类来说,这可能会很困难。我理解您的想法,但请思考如何实现这样一个全新的计划-除了完全清除所有Python对象之外,没有其他方法知道该做些什么,如果您想保留一些运行测试的状态,这是不可能的。您可以在单独的进程中运行测试,即使这样也不能确保在测试之间不会发生诸如更改文件之类的副作用。在一个新的docker容器中运行每个测试都可以做到这一点,但是如果您不希望出现这种开销,那么您必须确保自己清理更改的状态。