如何在 python 中的 @singleton decorated class 中模拟一个方法

How to mock a method inside a @singleton decorated class in python

class 本身在 init 方法中调用了一个 get_credentials 方法,我需要模拟它。使用单元测试进行模拟;

    from unittest import TestCase, mock
    from src.layer.utils.db import Db
        
    @singleton
    class Db:
    
        def __init__(self):
            self.get_credentials()
    
        def get_credentials(self):
            # stuff
            pass
    
    #Tried and failed:
    
    @mock.patch('src.layer.utils.db.Db.get_credentials',get_creds_mock) 
    
    @mock.patch.object(Db, 'get_credentials', get_credentials_mock) 



class DbMock:
    def get_credentials(self):
        pass

def get_credentials_mock(self):
    pass



class TestDb(TestCase):

    @mock.patch.object(Db, 'get_credentials', get_credentials_mock)
    def test_init(self):
        db = Db()
        self.assertIsInstance(db, Db)


The code of the @singleton decorator class:

    def singleton(cls):
        instances = {}
    
        def instance():
            if cls not in instances:
                instances[cls] = cls()
            return instances[cls]
    
        return instance

我需要模拟 get_credentials 函数,因为它与服务器通信,这在测试环境中是不允许的。所以,我必须 return json 令牌本身。

是否有任何可行的方法来模拟该功能?

您可以使用像 https://pypi.org/project/singleton-decorator/ 这样的解决方案来解决您的问题。

如果你不能交换单例装饰器,因为它是某种框架解决方案,使用这个特定的解决方案你就会陷入困境,因为你无法访问实例字典。

如果您出于任何原因不能使用其他包,但可以修改您对单例包装器的定义,您可以将其添加到您的单例代码中:

def singleton(cls):
        instances = {}
    
        def instance():
            if cls not in instances:
                instances[cls] = cls()
            return instances[cls]

        instance.__wrapped__ = cls
        return instance

然后您应该能够按照包中的介绍进行覆盖:

@mock.patch('wherever.Db.__wrapped__.get_credentials')