Sno*_*gus 61 python unit-testing monkeypatching class
我正在使用其他人编写的模块.我想修补__init__
模块中定义的类的方法.我发现如何执行此操作的示例都假设我自己会调用该类(例如,Monkey-patch Python类).然而,这种情况并非如此.在我的情况下,该类在另一个模块中的函数内被初始化.请参阅下面的(大大简化)示例:
thirdpartymodule_a.py
class SomeClass(object):
def __init__(self):
self.a = 42
def show(self):
print self.a
Run Code Online (Sandbox Code Playgroud)
thirdpartymodule_b.py
import thirdpartymodule_a
def dosomething():
sc = thirdpartymodule_a.SomeClass()
sc.show()
Run Code Online (Sandbox Code Playgroud)
mymodule.py
import thirdpartymodule_b
thirdpartymodule.dosomething()
Run Code Online (Sandbox Code Playgroud)
有没有办法修改__init__
方法,SomeClass
以便dosomething
从mymodule.py调用它时,例如,打印43而不是42?理想情况下,我能够包装现有方法.
我无法更改thirdpartymodule*.py文件,因为其他脚本依赖于现有功能.我宁愿不必创建我自己的模块副本,因为我需要做的改变非常简单.
编辑2013-10-24
我忽略了上面例子中的一个小而重要的细节.SomeClass
是这样导入的thirdpartymodule_b
:from thirdpartymodule_a import SomeClass
.
要做FJ建议的补丁我需要替换副本thirdpartymodule_b
,而不是thirdpartymodule_a
.例如thirdpartymodule_b.SomeClass.__init__ = new_init
.
And*_*ark 68
以下应该有效:
import thirdpartymodule_a
import thirdpartymodule_b
def new_init(self):
self.a = 43
thirdpartymodule_a.SomeClass.__init__ = new_init
thirdpartymodule_b.dosomething()
Run Code Online (Sandbox Code Playgroud)
如果您希望新的init调用旧的init new_init()
,请使用以下内容替换定义:
old_init = thirdpartymodule_a.SomeClass.__init__
def new_init(self, *k, **kw):
old_init(self, *k, **kw)
self.a = 43
Run Code Online (Sandbox Code Playgroud)
fal*_*tru 39
使用mock
库.
import thirdpartymodule_a
import thirdpartymodule_b
import mock
def new_init(self):
self.a = 43
with mock.patch.object(thirdpartymodule_a.SomeClass, '__init__', new_init):
thirdpartymodule_b.dosomething() # -> print 43
thirdpartymodule_b.dosomething() # -> print 42
Run Code Online (Sandbox Code Playgroud)
要么
import thirdpartymodule_b
import mock
def new_init(self):
self.a = 43
with mock.patch('thirdpartymodule_a.SomeClass.__init__', new_init):
thirdpartymodule_b.dosomething()
thirdpartymodule_b.dosomething()
Run Code Online (Sandbox Code Playgroud)
Mar*_*oft 13
另一种可能的方法与Andrew Clark 的方法非常相似,是使用wrapt库。除了其他有用的东西之外,这个库还提供了wrap_function_wrapper
和patch_function_wrapper
帮助器。它们可以这样使用:
import wrapt
import thirdpartymodule_a
import thirdpartymodule_b
@wrapt.patch_function_wrapper(thirdpartymodule_a.SomeClass, '__init__')
def new_init(wrapped, instance, args, kwargs):
# here, wrapped is the original __init__,
# instance is `self` instance (it is not true for classmethods though),
# args and kwargs are tuple and dict respectively.
# first call original init
wrapped(*args, **kwargs) # note it is already bound to the instance
# and now do our changes
instance.a = 43
thirdpartymodule_b.do_something()
Run Code Online (Sandbox Code Playgroud)
或者有时您可能想使用wrap_function_wrapper
它不是装饰器,但其他方式的工作方式相同:
def new_init(wrapped, instance, args, kwargs):
pass # ...
wrapt.wrap_function_wrapper(thirdpartymodule_a.SomeClass, '__init__', new_init)
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
43228 次 |
最近记录: |