这里是龙。你已被警告过了。
我正在考虑创建一个新的库,试图帮助编写更好的测试套件 为了做到这一点,其中一个功能是一个功能,它验证正在使用的任何不是测试运行器和system under test的对象都有一个测试对象(模拟对象,存根,伪造或一个假人)。如果测试人员想要活动对象并因此减少测试隔离,则必须明确指定。
我看到这样做的唯一方法是覆盖内置type()
函数,这是默认的元类。
新的默认元类将检查测试双重注册表字典,以查看它是否已被测试双重替换,或者是否指定了活动对象。
当然,这不可能通过Python本身实现:
>>> TypeError: can't set attributes of built-in/extension type 'type'
有没有办法在测试套件运行之前干预Python的元类查找(可能还有Python)?
也许使用字节码操作?但到底是怎么回事?
答案 0 :(得分:9)
以下是不可取的,你会遇到很多问题和角落实现你的想法,但是在Python 3.1及更高版本中,你可以通过覆盖{挂钩自定义类创建过程{1}}内置钩子:
__build_class__
这仅限于自定义类 ,但它确实为您提供了一个全能的钩子。
对于3.1之前的Python版本,您可以忘记挂钩创建类。如果没有定义元类,则C build_class
function直接使用C类型import builtins
_orig_build_class = builtins.__build_class__
class SomeMockingMeta(type):
# whatever
def my_build_class(func, name, *bases, **kwargs):
if not any(isinstance(b, type) for b in bases):
# a 'regular' class, not a metaclass
if 'metaclass' in kwargs:
if not isinstance(kwargs['metaclass'], type):
# the metaclass is a callable, but not a class
orig_meta = kwargs.pop('metaclass')
class HookedMeta(SomeMockingMeta):
def __new__(meta, name, bases, attrs):
return orig_meta(name, bases, attrs)
kwargs['metaclass'] = HookedMeta
else:
# There already is a metaclass, insert ours and hope for the best
class SubclassedMeta(SomeMockingMeta, kwargs['metaclass']):
pass
kwargs['metaclass'] = SubclassedMeta
else:
kwargs['metaclass'] = SomeMockingMeta
return _orig_build_class(func, name, *bases, **kwargs)
builtins.__build_class__ = my_build_class
值,它永远不会从type()
模块中查找它,因此您无法覆盖它。
答案 1 :(得分:2)
我喜欢你的主意,但我认为你的目标略有偏差。如果代码调用库函数而不是类,该怎么办?你的假类型()永远不会被调用,你永远不会被告知你没有模仿那个库函数。 Django和任何真正的代码库都有很多实用功能。
我建议你以Python补丁的形式编写所需的解释器级支持。或者你可能会发现在PyPy的代码库中添加这样的钩子更容易,这是用Python本身编写的,而不是弄乱Python的C源。
我刚刚意识到Python解释器包含一套全面的工具,可以让任何一段Python代码逐步执行任何其他代码,检查它对每个函数调用的作用,甚至每个函数调用。如果需要,正在执行Python行。
sys.setprofile
应该足以满足您的需求。有了它,你可以安装一个钩子(一个回调),它将被通知目标程序正在进行的每个函数调用。您无法使用它来更改目标程序的行为,但您可以收集有关它的统计信息,包括“模拟覆盖率”指标。
Python关于Profilers的文档介绍了许多基于sys.setprofile
构建的模块。您可以研究他们的来源,看看如何有效地使用它。
如果结果不够,仍然有sys.settrace
,这是一种严厉的方法,允许您逐步执行目标程序的每一行,检查其变量并修改其执行。标准模块bdb.py
构建在sys.settrace
之上,并实现了一组标准的调试工具(断点,步入,跳过等)。它由pdb.py
使用,它是命令行调试器,以及其他图形调试器。
有了这两个钩子,你应该没事。