单元测试Python3元类

单元测试Python3元类,python,python-3.x,unit-testing,python-import,metaclass,Python,Python 3.x,Unit Testing,Python Import,Metaclass,我有一个元类,它在加载类时设置一个类属性my_new_属性。该文件将命名为my_meta,代码如下 def remote_function(): # Get some data from a request to other site return 'remote_response' class MyMeta(type): def __new__(cls, *args, **kwargs): print("It is in") obj = super().__new

我有一个元类,它在加载类时设置一个类属性
my_new_属性
。该文件将命名为
my_meta
,代码如下

def remote_function():
  # Get some data from a request to other site
  return 'remote_response'

class MyMeta(type):
  def __new__(cls, *args, **kwargs):
    print("It is in")
    obj = super().__new__(cls, *args, **kwargs)
    new_value = remote_function()
    setattr(obj, 'my_new_property', new_value)
    return obj
设置属性的功能可以正常工作,但是在编写测试文件
tests.py
时,只有一行代码:

from my_meta import MyMeta
执行元代码。因此,它执行real方法
远程\u函数


问题是。。。由于元代码仅通过使用测试文件中的
import
执行,我如何模拟方法
remote\u函数

如您所示导入文件不会触发元类代码的执行

但是,如果有一个类使用这个元类,那么导入任何文件(包括元类所在的文件)都会运行元类
\uuuuu new\uuuuuuu
方法中的代码,因为解析用
class
语句定义的类体只需要:调用元类来创建一个新的类实例

因此,建议是:如果不能以无缝、无害的方式实现,那么不要使用元类
\uuuuu new\uuuuu
\uuuuuuu init\uuuuuuuuuu
方法来触发副作用,比如访问远程内容。不仅测试,而且在pythonshell中导入应用程序的模块也会触发该行为

您可以在元类中使用一个方法来初始化远程值,当您准备实际使用这些值时,您可以显式地调用这样一个“remote_init”——如中所示

class MyMeta(type):
  def __new__(cls, *args, **kwargs):
    print("It is in")
    obj = super().__new__(cls, *args, **kwargs)
    new_value = remote_function()
    setattr(obj, 'my_new_property', new_value)
    return obj

  def remote_init(cls):
      if hasattr(cls, "my_new_property"): 
           return
      cls.my_new_property = remote_function()
放置在元类中的远程_init方法的行为类似于实例化类的类方法,但在类实例中不可见(对于dir或属性检索)。 这是最安全的做法

如果要避免显式步骤(这是可以理解的),可以在配置文件中使用设置,并在remote_函数中测试是触发实际的网络代码,还是只返回本地的伪值。然后,您可以针对测试/暂存/生产进行不同的配置

最后,您可以在另一个模块中分离
remote_方法
,首先导入该方法,用
unitttest.mock.patch
修补它,然后导入包含模块的元类-当它运行并调用该方法时,它将只是打包版本。这将适用于您的测试,但不会解决您在其他情况下触发副作用的问题(如加载此模块的其他测试)


当然,要实现这一点,您必须在
mock.patch
处于活动状态的区域中导入包含元类和在测试函数中定义的任何类的模块,而不是在文件顶部导入它。在测试方法中导入东西以控制导入过程本身是没有问题的

导入文件不会神奇地调用该文件中定义的函数。请发布一个。几乎可以肯定的是,您还导入了使用MyMeta作为元类定义类的内容。