我正在尝试在Python中使用抽象工厂,最少使用以下3个文件进行复制:
from factory import Factory
def test_factory():
factory = Factory.makeFactory()
product = factory.makeProduct('Hi there')
print(product)
if __name__ == '__main__':
test_factory()
from abc import ABCMeta, abstractmethod
from product import ConcreteProduct
class Factory(metaclass=ABCMeta):
@classmethod
@abstractmethod
def makeProduct(cls):
pass
@classmethod
def makeFactory(cls):
return ConcreteFactory()
class ConcreteFactory(Factory):
@classmethod
def makeProduct(cls, message):
return ConcreteProduct(message)
class ConcreteProduct(object):
def __init__(self, message):
self._message = message
def __str__(self):
return self._message
我弄清楚的是如何模拟此代码以验证是否使用适当的值调用ConcreteProduct.__init__
。由于测试文件永远不会看到product.py
,我不知道如何实现这一点,或者甚至可能。我怀疑我的设计存在一些根本性的错误。
答案 0 :(得分:0)
到目前为止,我已经找到了@Michele dAmico的回答导致的解决方案,而且非常接近他。
test_factory.py
变为:
from factory import Factory
from unittest.mock import patch
@patch('product.ConcreteProduct.__init__', return_value=None)
def test_factory(mock_init):
factory = Factory.makeFactory()
product = factory.makeProduct('Hi there')
mock_init.assert_called_with('Hi there')
if __name__ == '__main__':
test_factory()
请注意,我修补了product.
,而不是factory.
,所以我基本上回避factory.py
并嘲笑我知道要导入的内容。我不知道如何以这种方式打破封装,但说实话,这就是我对嘲笑的感觉。
我比其他答案更喜欢这个,因为它更短,因为根据the mock docs它可能很危险:
默认情况下,补丁将无法替换不存在的属性。如果 你传入create = True,并且该属性不存在,补丁会 调用修补函数时为您创建属性,和 之后再删除它。这对于编写测试非常有用 生产代码在运行时创建的属性。它离开了 默认,因为它可能是危险的。打开它就可以写了 通过针对实际不存在的API传递测试!
我当然会对进一步的讨论感兴趣,因为我仍然有一种感觉,我可以学习一些更好的设计方法来使它更清洁。