我有一个非常简单的python类和一个构造函数:
from utils.util import Singleton
class VaultAuth(object):
__metaclass__ = Singleton
def __init__(self, prefix_path, address):
self.path = prefix_path
self.vault_url = address
self.is_authenticated = False
def get_secrets(self, region):
print self.is_authenticated
if not self.is_authenticated:
raise RuntimeError("Failed to fetch secrets")
else:
return True
其中Singleton类如下所示:
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
要编写单元测试,我有:
@pytest.mark.unit_test
def test_get_secrets(monkeypatch):
def mock_init_auth_false(self, *args, **kwargs):
self.path = "dummy_path"
self.vault_url = "dummy_url"
self.is_authenticated = False
def mock_init_auth_true(self, *args, **kwargs):
self.path = "dummy_path"
self.vault_url = "dummy_url"
self.is_authenticated = True
# Negative case - auth is false
monkeypatch.setattr(vault1.VaultAuth, "__init__", mock_init_auth_false)
secrets_manager = vault1.VaultAuth(prefix_path="prefix", address="https://vault")
with pytest.raises(RuntimeError) as exception:
secret_data = secrets_manager.get_secrets(region="test_region")
assert "Failed to fetch secrets" in str(exception.value)
monkeypatch.undo()
# Positive case - auth is true
monkeypatch.setattr(vault1.VaultAuth, "__init__", mock_init_auth_true)
secrets_manager = vault1.VaultAuth(prefix_path="prefix", address="https://vault")
assert secrets_manager.get_secrets(region="test_region")
根据预期,第一个测试打印的值为False,但第二个测试也打印为False。如果我颠倒测试的顺序,两个都打印True
。有什么建议吗?这个班是单身汉。如何测试单例类函数?你知道吗
好吧,您使用的是
Singleton
模式,所以只有一个类的实例,__init__
方法在这里不会被调用两次。你知道吗因为您正在单元测试
get_secrets()
方法,所以只需调整测试的singleton实例的状态:但是,上面的测试很容易出现其他问题,因为Singleton类是为Python进程的生存期创建的。如果其他测试使用
vault1.VaultAuth(...)
任何具有不同参数的地方,那么这些测试就会有问题,因为它们被赋予相同的单例实例。你知道吗您当然可以在测试中使用singleton类的escape hatch方法;
Singleton._clear_singleton()
方法将删除给定类的缓存实例,只需调用ClassObject._clear_singleton()
:因此,您可以至少清除现有的单例实例:
try: ... finally:
模式确保为测试创建的单例至少被清除。您也可以将其作为pytest夹具:但这只会清除每个测试函数的单例,而不是在测试过程中多次清除。你知道吗
但是,与模仿
__init__
不同的是,您可以将子类化为类,因为您将使用不同的类。它们分别作为单件缓存:但是如果类采用特定的参数(前缀、地址),则看起来您在这里使用了错误的模式。你知道吗
您可能希望基于参数缓存实例,因此每个
(prefix_path, address)
对有一个实例:这将为前缀和地址的每个唯一组合创建一个实例。注意,它没有
__init__
方法!我故意这么做的,您可以使用一个,但是如果从__new__
返回,它将在VaultAuth
的任何实例或其子类上调用,即使该实例是在cls._vaults
映射之前创建的,并且刚刚从cls._vaults
映射返回。你知道吗无论如何,您可以在测试中使用它,只需使用编造的参数,并更改属性以适合您的测试:
通过使用特定于测试的参数,创建的实例不太可能干扰其他测试,并且可以为不同的地址创建单独的保险库。你知道吗
您是否尝试过在第二个测试用例之前简单地删除singleton实例?你知道吗
相关问题 更多 >
编程相关推荐