如何测试抽象工厂

时间:2015-09-18 04:30:03

标签: python python-3.x factory abstract-factory

我正在尝试在Python中使用抽象工厂,最少使用以下3个文件进行复制:

test_factory.py

from factory import Factory

def test_factory():
    factory = Factory.makeFactory()
    product = factory.makeProduct('Hi there')
    print(product)

if __name__ == '__main__':
    test_factory()

factory.py

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)

product.py

class ConcreteProduct(object):
    def __init__(self, message):
        self._message = message
    def __str__(self):
        return self._message

我弄清楚的是如何模拟此代码以验证是否使用适当的值调用ConcreteProduct.__init__。由于测试文件永远不会看到product.py,我不知道如何实现这一点,或者甚至可能。我怀疑我的设计存在一些根本性的错误。

1 个答案:

答案 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传递测试!

我当然会对进一步的讨论感兴趣,因为我仍然有一种感觉,我可以学习一些更好的设计方法来使它更清洁。

相关问题