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

dre*_*dre 4 python stub

我有一个使用RealClass的模块,因此它是一个我无法访问的内部依赖项.

我希望能够创建一个FakeClass,它取代RealClass的功能进行测试.我不想替换整个班级的个别方法.

我看了一下似乎是我想要的胡茬,但我想知道mox或任何其他模拟框架是否具有此功能?或者你建议使用什么?也许软糖,猴子补丁?只是寻找这些东西的最佳实践.任何有用的例子都很棒.

伪代码:

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
Run Code Online (Sandbox Code Playgroud)

更新:

这是我发现的一种方式.它不完美,但它的工作原理.

例:

fake = FakeClass()
stub = stubout.StubOutForTesting()
stub.Set(RealClass, 'method_1', fake.method_1)
stub.Set(RealClass, 'method_2', fake.method_2)
Run Code Online (Sandbox Code Playgroud)

cJ *_*oub 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")
Run Code Online (Sandbox Code Playgroud)

命名空间允许您修补导入模块内导入模块的内容...

请注意,上述方法不适用于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")
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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