如何在Python中为测试虚拟一个模块中的类?
我有一个模块在用,它依赖于一个叫做RealClass的东西,但我没有权限去查看这个类。
我想创建一个FakeClass,来替代RealClass的功能,以便进行测试。我不想只替换某个方法,而是想替换整个类。
我查了一下stubble,看起来它能满足我的需求,但我想知道mox或者其他的模拟框架是否也有这个功能?或者你有什么建议可以用的?也许是fudge,或者是猴子补丁?我只是想了解一下这方面的最佳实践。如果能提供一些有用的例子就更好了。
伪代码:
from module import RealClass
class FakeClass
methodsFromRealClassOverridden
class Test(unittest.TestCase):
setup()
teardown()
test1()
stub(RealClass, FakeClass) // something like this, but really just want the functionality
classThatUsesRealClass // now will use FakeClass
更新:
我找到了一种方法来实现这个功能。虽然不是完美的,但确实有效。
示例:
fake = FakeClass()
stub = stubout.StubOutForTesting()
stub.Set(RealClass, 'method_1', fake.method_1)
stub.Set(RealClass, 'method_2', fake.method_2)
1 个回答
我觉得你想听听大家的看法和经验,所以我来分享一下我的想法。
正如你所注意到的,Python有很多测试工具、类和框架,但大多数情况下,由于Python简单、灵活和开放,你可能会选择使用一些临时的测试案例,这些测试通常是在接口层面进行一些简单的替换和一点unittest的使用……直到你开始使用框架。
在进行测试或替换时,使用“猴子补丁”并没有什么不好的地方:
#!/usr/bin/env python
# minimal example of library code
class Class:
""" a class """
def method(self, arg):
""" a method that does real work """
print("pouet %s" % arg)
#!/usr/bin/env python
# minimal example for stub and tests, overriding/wrapping one method
from Class import Class
Class._real_method = Class.method
def mymethod(self, arg):
# do what you want
print("called stub")
# in case you want to call the real function...
self._real_method(arg)
Class.method = mymethod
# ...
e = Class()
e.method("pouet")
命名空间可以让你在导入的模块中进行补丁操作……
需要注意的是,上面的方法在C模块的类中是行不通的。对于这些情况,你可以使用一个包装类,通过getattr/setattr来过滤类成员的名称,并从包装类返回重新定义的成员。
#!/usr/bin/env python
# Stupid minimal example replacing the sys module
# (not very useful / optimal, it's just an example of patching)
import sys
class SysWrap():
real = sys
def __getattr__(self, attr):
if attr == 'stderr':
class StdErr():
def write(self, txt):
print("[err: %s]" % txt)
return StdErr()
print("Getattr %s" % attr)
return getattr(SysWrap.real, attr)
sys = SysWrap()
# use the real stdout
sys.stdout.write("pouet")
# use fake stderr
sys.stderr.write("pouet")
一旦你厌倦了临时测试,你会发现一些更高级的工具,比如你提到的那些(stubble, fudge)会很有用,但要想高效地使用它们,你首先得理解它们解决了什么问题,并接受它们在背后自动做的事情。
可能会有一部分临时的猴子补丁仍然存在,因为它更容易理解,而且所有工具都有一些局限性。
工具可以增强你的能力,但你必须深入理解它们,才能高效使用。
在决定是否使用某个工具时,一个重要的方面是,当你传递一段代码时,你也在传递整个环境(包括测试工具)。下一个人可能没有你那么聪明,可能会因为你的测试工具太复杂而跳过测试。一般来说,你会希望在软件中避免使用太多的依赖。
最后,我认为如果你只是使用unittest和临时测试/猴子补丁,只要你的代码能正常工作,没人会在意。毕竟你的代码可能并没有那么复杂。