如何在Python中的模块中存根用于测试?

时间:2011-09-29 17:40:33

标签: python stub

我有一个使用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 个答案:

答案 0 :(得分:6)

我认为你需要意见/经验,所以我只给我2美分。

正如您所注意到的,有一些Python测试工具/类/框架,但大部分时间考虑到Python的简单性/动态性/开放性,您将限制自己使用特定的相关测试用例,这些测试用例涉及接口处的存根等级,以及一些单元测试...直到你开始使用框架。

猴子修补没有什么贬义,特别是在进行测试/剔除时:

#!/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")

一旦你厌倦了进行临时测试,你会发现更高级别的东西,比如你提到的那些(胡茬,软糖)很有用,但要享受它们并有效地使用它们你必须首先看到问题他们解决并接受他们在幕后所做的所有自动操作。

可能会留下特定猴子补丁的一部分,它更容易理解,并且所有工具都有一些限制。

工具赋予您权力,但您必须深入了解它们才能有效地使用它们。

决定是否使用工具时的一个重要方面是,当您传输一大块代码时,您会传输整个环境(包括测试工具)。 下一个人可能不像你那么聪明并且跳过测试,因为你的测试工具对他来说太复杂了。 通常,您希望避免在软件中使用大量依赖项。

最后,如果您只使用单元测试和临时测试/猴子修补,我认为如果你的东西有效,没有人会打扰你。 无论如何,您的代码可能不是 复杂。