python - 如何模拟单例类方法

标签 python python-2.7 unit-testing mocking patch

假设我们有以下结构:

class A():
    class __A():
        def __to_be_mocked(self):
            #something here
    def __init__(self):
        with A.lock:
            if not A.instance:
                A.instance = A.__A()

    def __getattr__(self,name):
        return getattr(self.instance,name)

现在我们要模拟函数__to_be_mocked。我们如何模拟它作为mock.patch.object接受的目标是package.module.ClassName 。我已经尝试了所有方法,例如

target = A.__A
target = A.___A

还有更多。

编辑:

我用

解决了它
target=A._A__A and attribute as '_A__to_be_mocked`

现在的问题是 __to_be_mocked__A 里面,所以它不应该是 ___A__to_be_mocked 吗。

是因为A中的setattribute还是A中的__init__

最佳答案

我在 python 中模拟了很多东西,在做了很多次之后我可以说:

  1. 从不 模拟/修补 __something 属性(又称 private 属性)
  2. 避免模拟/修补_something 属性(又名protected 属性)

私有(private)

如果您模拟私有(private)事物,您会混淆生产和测试代码。当您进行此类模拟时,总有一种方法可以通过修补或模拟公共(public)或 protected 内容来获得相同的行为。

为了更好地解释我所说的混淆生产代码和测试代码的意思,我可以使用您的示例:修补 A.__B.__to_be_mocked() (我替换了 __A 内部类通过 __B 使其更清楚)你需要写一些像

patch('amodule.A._A__B._B__to_be_mocked')

现在,通过修补 __to_be_mocked,您可以在测试中传播 ABto_be_mocked 名称:即正是我所说的纠结代码。因此,如果您需要更改某个名称,您应该进入所有测试并更改您的补丁,并且没有任何重构工具可以建议您更改 _A__B._B 字符串。

现在,如果你是一个好人并且把你的测试搞得一清二楚,那么你可以只在几个点上出现这些名字,但如果它是一个单例,我敢打赌它会像蘑菇一样被发现。

我想指出 private 和 protected 与某些安全问题无关,它们只是让您的代码更清晰的一种方式。这一点在 Python 中非常清楚,您无需成为黑客即可更改私有(private)或 protected 属性:这些约定在这里只是为了帮助您阅读可以说 Oh great 的代码!我不需要了解它是什么......它只是肮脏的工作。恕我直言,python 中的私有(private)属性无法实现此目标(__ 太长,看到它真的很困扰我)并且 protected 就足够了。

旁注:理解 python 私有(private)命名的小例子:

>>> class A():
...  class __B():
...   def __c(self):
...    pass
... 
>>> a = A()
>>> dir(a)
['_A__B', '__doc__', '__module__']
>>> dir(a._A__B)
['_B__c', '__doc__', '__module__']

回到你的案例:你的代码如何使用 __to_be_mocked() 方法?是否可以通过在 A(而不是 A.__A)类中修补/模拟其他东西来产生相同的效果?

最后,如果您正在模拟私有(private)方法来感知要测试的东西,那么您来错地方了:永远不要测试肮脏的工作,它应该/可能/可以在不改变您的测试的情况下改变。您需要的是测试代码行为,而不是代码的编写方式。

protected

如果你需要测试、补丁或模拟 protected 东西,也许你的类隐藏了一些合作者:测试它并使用你的测试来重构你的代码,然后清理你的测试。

免责声明

的确:我在我的测试中散布了这种废话,然后当我明白我可以做得更好时,我会努力将其删除。

关于python - 如何模拟单例类方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35569348/

相关文章:

python - 如何使用Python请求使用offset参数对api调用进行分页

python-2.7 - 如何在 Windows 上安装 python 2.7 的 pymedia?

python - 如何断言列表中确实包含预期的元素?

python - 按行中的值从 pandas 数据透视表中过滤

Python 手动/独立/可移植 Windows 安装

python - Odoo 如何删除模型中的“创建”按钮而不影响 One2many?

java - 检查单元测试是否委托(delegate)了所有方法

javascript - 模拟 Angular 模型的 $http.put 结果 - 单元测试

python - 将应用程序代码放在虚拟环境目录中是一个坏主意吗?

python - 确定在 python 中表示为字符串的值的类型