简体   繁体   English

如何模拟单例类方法

[英]How to mock a singleton class method

Suppose we have the following structure: 假设我们具有以下结构:

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)

Now we want to mock the function __to_be_mocked .How can we mock it as the target accepted by mock.patch.object is package.module.ClassName .I have tried all methods like 现在我们要模拟__to_be_mocked函数。我们如何模拟它作为模拟对象接受的mock.patch.object package.module.ClassName 。我已经尝试了所有方法,例如

target = A.__A
target = A.___A

and many more. 还有很多。

EDIT: 编辑:

I solved it using 我用解决了

target=A._A__A and attribute as '_A__to_be_mocked`

Now the question is __to_be_mocked is inside __A so shouldn't it be ___A__to_be_mocked . 现在的问题__to_be_mocked里面__A所以应该不是被___A__to_be_mocked

Is it because of setattribute in A or __init__ in A? 是因为Asetattribute还是A __init__

I mocked a lot of things in python and after did it lot of times I can say: 我在python中嘲笑了很多东西,经过很多次我可以说:

  1. NEVER mock/patch __something attributes (AKA private attributes) 永远不会模拟/补丁__something属性(又名私有属性)
  2. AVOID to mock/patch _something attributes (AKA protected attributes) 避免模拟/修补_something属性(又_something 受保护的属性)

Private 私人的

If you mock private things you'll tangled production and test code. 如果您嘲笑私人事物,那么您将纠结于生产和测试代码。 When you do this kind of mocks there is always a way to obtain the same behavior by patching or mocking public or protected stuffs. 当您进行这种模拟时,总有一种方法可以通过修补或模拟公共或受保护的东西来获得相同的行为。

To explain better what I mean by tangling production and test code I can use your example: to patch A.__B.__to_be_mocked() (I replaced __A inner class by __B to make it more clear) you need to write something like 为了更好地解释彼此缠绕的生产和测试代码,我可以用你的榜样我的意思:修补A.__B.__to_be_mocked()我换成__A通过内部类__B ,使之更加清楚),你需要写类似

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

Now by patching __to_be_mocked you are spreading A , B and to_be_mocked names in your test: that is exactly what I mean to tangled code. 现在通过修补__to_be_mocked您可以在测试中散布ABto_be_mocked名称:这正是我要纠结的代码的意思。 So if you need to change some name you should go in all your test and change your patches and no refactoring tool can propose to you to change _A__B._B string. 因此,如果您需要更改某些名称,则应该进行所有测试并更改补丁,并且没有任何重构工具可以建议您更改_A__B._B字符串。

Now if you are a good guy and take your tests clean you can have just a few points where these names come out but if it is a singleton I can bet that it will spot out like mushrooms. 现在,如果您是一个好人,并且将自己的测试清理干净,那么可以说出这些名字的几点,但是如果是单身,我敢打赌,它会像蘑菇一样出现。

I would like to point out that private and protected have nothing to do with some security concern but are just way to make your code more clear. 我想指出,私有和受保护与某些安全问题无关,而只是使代码更清晰的一种方法。 That point is crystal clear in python where you don't need to be a hacker to change private or protected attributes: these conventions are here just to help you on reading code where you can say Oh great! 这一点在python中非常清楚,您无需成为黑客即可更改私有或受保护的属性:这些约定只是为了帮助您阅读代码,在这里您可以说哦,太好了! I don't need to understand what is it ... it just the dirty work . 我不需要了解它是什么...仅仅是肮脏的工作 IMHO private attributes in python fails this goal ( __ is too long and see it really bother me) and protected are just enough. python中的恕我直言私有属性无法实现此目标( __太长了,看到它真的困扰我),并且受保护就足够了。

Side note: little example to understand python's private naming: 旁注:了解python私有命名的小例子:

>>> 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 come back at your case: How your code use __to_be_mocked() method? 回到您的情况:您的代码如何使用__to_be_mocked()方法? is it possible to have the same effect by patch/mock something else in A (and not A.__A ) class? 通过修补/模拟A (而不是A.__A )中的其他内容,是否可能具有相同的效果?

Finally, if you are mocking private method to sense something to test you are in the wrong place: never test the dirty work it should/may/can change without change your tests. 最后,如果您在嘲笑专用方法以感觉到要测试的东西,那么您来错了地方:永远不要测试那些肮脏的工作 ,如果不更改测试,它应该/可能/可以改变。 What you need is to test code behavior and not how it is written. 您需要的是测试代码行为,而不是代码编写方式。

Protected 受保护的

If you need test, patch or mock protected stuffs maybe your class hide some collaborators: test it and use your test to refactor your code then clean your tests. 如果您需要测试,补丁或模拟保护的东西,也许您的班级可能隐藏了一些合作者:进行测试并使用测试来重构代码,然后清理测试。

Disclaimer 免责声明

Indeed: I spread this kind of crap in my tests and then I fight to remove it when I understand that I can do it better. 确实:我在测试中传播了这种废话,然后在得知自己可以做得更好的情况下努力将其删除。

Class & instance members starting with double underscores have their names rewritten to prevent collisions with same-name members in parent classes, making them behave as if "private". 以双下划线开头的类和实例成员的名称被重写,以防止与父类中的同名成员发生冲突,从而使其表现得像“私有”。 So __B here is actually accessible as A._A__B . 因此__B实际上可以作为A._A__B访问。 (Underscore, class name, double underscored member name). (下划线,类名,双下划线的成员名)。 Note that if you use the single-underscore convention ( _B ), no rewriting happens. 请注意,如果使用单下划线约定( _B ),则不会进行任何重写。

That being said, you'll rarely see anyone actually use this form of access and especially not in prod code as things are made "private" for a reason. 话虽这么说,您很少会看到有人真正使用这种访​​问方式, 尤其是在产品代码中,因为某种原因将它们“私有化”,所以很少使用。 For mocking, maybe, if there's no better way. 如果没有更好的方法,也许可以嘲笑。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM