如何在 Python 模块中存根类以进行测试?

发布于 2024-12-07 09:56:15 字数 956 浏览 1 评论 0原文

我正在使用一个使用 RealClass 的模块,因此它是我无权访问的内部依赖项。

我希望能够创建一个 FakeClass 来替换 RealClass 的功能以进行测试。我不想替换单个方法,而是替换整个类。

我查看了 stubble 这似乎是我想要的,但我想知道是否 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

更新:

这是我发现的一种方法。它并不完美,但它有效。

例子:

fake = FakeClass()
stub = stubout.StubOutForTesting()
stub.Set(RealClass, 'method_1', fake.method_1)
stub.Set(RealClass, 'method_2', fake.method_2)

I have a module I am using which uses RealClass, so it is an internal dependency I don't have access to.

I want to be able to create a FakeClass which replaces the functionality of the RealClass for testing. I don't want to replace individual methods but the entire class.

I looked at stubble which seems to be what I want but I was wondering if mox or any of the other mocking frameworks have this functionality? Or what would you suggest to use? Maybe fudge, monkey-patching? Just looking for best practices with this stuff. Also any useful examples would be awesome.

Pseudo code:

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

UPDATE:

Here's one way I found to do it. It isn't perfect but it works.

Example:

fake = FakeClass()
stub = stubout.StubOutForTesting()
stub.Set(RealClass, 'method_1', fake.method_1)
stub.Set(RealClass, 'method_2', fake.method_2)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

暮色兮凉城 2024-12-14 09:56:15

我认为你想要意见/经验,所以我只给出我的 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")

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

临时猴子修补的一部分可能会保留,只是更容易理解,并且所有工具都有一些限制。

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

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

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

I think you want opinions/experiences so I'm just giving my 2 cents.

As you noticed there are a few Python testing tools/classes/frameworks, but most of the time given the simplicity/dynamism/openness of Python you will limit yourself to using ad-hoc relevant test cases which involve stubbing at the interface level, and a bit of unittest... until you start using the frameworks.

There is nothing pejorative about monkey-patching, especially when it comes to performing testing/stubbing:

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

Namespaces will allow you to patch stuff inside of imported modules inside of imported modules...

Note that the above method does not work with classes in C modules.
For them you can use a wrapper class that filters on class member names using getattr/setattr, and returns the redefined members from the wrapper class.

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

Once you are becoming tired of performing ad-hoc testing, you'll find higher level stuff such as the ones you mentioned (stubble, fudge) useful, but to enjoy them and use them efficiently you have to first see the problems they solve and accept all the automatic stuff they do under the hood.

It is probable that a part of ad-hoc monkey patching will remain, it's just easier to understand, and all the tools have some limitations.

Tools empower you but you have to deeply understand them to use them efficiently.

An important aspect when deciding whether to use a tool or not is that when you transmit a chunk of code, you transmit the whole environment (including testing tools).
The next guy might not be as smart as you and skip the testing because your testing tool is too complex for him.
Generally you want to avoid using a lot of dependencies in your software.

In the end, I think that nobody will bother you if you just use unittest and ad-hoc tests/monkey-patching, provided your stuff works.
Your code might not be that complex anyway.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文