Pytest夹具为元类

时间:2019-02-20 07:27:47

标签: python pytest metaclass

是否存在一种优雅的方法来定义在类创建之前设置的fixture,以便元类可以使用它们? 更精确地说,在我的用例中,我有一个元类,它根据模块级文件上的某些设置来创建该类。

settings.py:

SETTING_1 = True
SETTING_2 = False
...

在测试中,我想更改灯具中的某些设置,并根据这些设置,我的元类应创建该类。

我还没有在文档中找到有关它的东西。

1 个答案:

答案 0 :(得分:0)

元类以及使用这些元类的类都是在执行包含class语句主体的代码行时创建的。

考虑到这一点,测试类或元类没有什么不同-如果class语句处于模块级别,则在首次导入模块时将构建类和元类-这意味着您必须退出您(或测试框架的)在测试之间进行重新构建的方式。

但是,如果确实将它们放在函数主体中,则在调用函数时将重新构建它们。如果它们是Fixture函数,则每次使用Fixture时都会对其进行重建(尽管我认为Pytest会进行一些Fixture缓存-注意这一点)

另一方面,如果应用程序代码中包含元类和使用then的类,则您不能将它们放在要重新创建的函数体内。在这种情况下,您将必须谨慎设计imp.reload函数的使用-这将使模块级别的代码在每次调用时都重新运行。您可以在Fixture函数中调用imp.reload(<module>),但是在Fixture运行期间要小心地将所有引用重新绑定到这些元类(以及使用它们的类)。

因此,如果您的应用程序代码中包含以下内容:

# module_b
from module_a import SETTING_1, SETTING_2

class Meta(type):
    def __init__(mcls, name, bases, ns, **kw):
         # code that make use of SETTING_1 and SETTING_2
         ...

class A(metaclass=Meta):
    ...

测试装置模块:

import pytest
from unittest import mock

@pytest.fixture
def recreate_metaclass():
    from imp import reload
    # Drawback: fixtures file have to know and manually imported here 
    import test_module_1, ...
    import module_b
    with mock.patch("module_a.SETTING_1", val_1), mock.patch("module_a.SETTING_2" val_2):
        module_b = reload(module_b)
        # rebind module_a inside test modules
        test_module_1.module_b = module_b
        ...