避免执行模拟类的__init__

时间:2014-11-05 15:12:05

标签: python python-2.7 mocking python-unittest python-mock

我有一个昂贵的__init__函数的类。我不希望从测试中调用此函数。

出于本示例的目的,我创建了一个在__init__中引发异常的类:

class ClassWithComplexInit(object):

    def __init__(self):
        raise Exception("COMPLEX!")

    def get_value(self):
        return 'My value'

我有第二个类构造ClassWithComplexInit的实例并使用它的函数。

class SystemUnderTest(object):

    def my_func(self):
        foo = ClassWithComplexInit()
        return foo.get_value()

我正在尝试围绕SystemUnderTest#my_func()编写一些单元测试。我遇到的问题是无论我如何尝试模拟ClassWithComplexInit__init__函数总是被执行并引发异常。

class TestCaseWithoutSetUp(unittest.TestCase):

    @mock.patch('mypackage.ClassWithComplexInit.get_value', return_value='test value')
    def test_with_patched_function(self, mockFunction):
        sut = SystemUnderTest()
        result = sut.my_func()  # fails, executes ClassWithComplexInit.__init__()
        self.assertEqual('test value', result)

    @mock.patch('mypackage.ClassWithComplexInit')
    def test_with_patched_class(self, mockClass):
        mockClass.get_value.return_value = 'test value'
        sut = SystemUnderTest()
        result = sut.my_func()  # seems to not execute ClassWithComplexInit.__init__()
        self.assertEqual('test value', result)  # still fails
        # AssertionError: 'test value' != <MagicMock name='ClassWithComplexInit().get_value()' id='4436402576'>

上面的第二种方法是我从this similar Q&A获得的方法,但它也没有用。它似乎似乎不运行__init__函数,但我的断言失败,因为结果最终是一个模拟实例,而不是我的值。

我还尝试使用patchsetUp函数startstop函数中配置class TestCaseWithSetUp(unittest.TestCase): def setUp(self): self.mockClass = mock.MagicMock() self.mockClass.get_value.return_value = 'test value' patcher = mock.patch('mypackage.ClassWithComplexInit', self.mockClass) patcher.start() self.addCleanup(patcher.stop) def test_my_func(self): sut = SystemUnderTest() result = sut.my_func() # seems to not execute ClassWithComplexInit.__init__() self.assertEqual('test value', result) # still fails # AssertionError: 'test value' != <MagicMock name='mock().get_value()' id='4554658128'> 个实例。

__init__

这似乎也避免了我的get_value.return_value功能,但我为get_value()设置的值没有得到尊重,MagicMock仍在返回__init__个实例。

如何模拟具有复杂patch的类,该类由我的测试代码实例化?理想情况下,我想要一个适用于TestCase类中许多单元测试的解决方案(例如,不需要每次测试2.7.6)。

我使用的是Python版{{1}}。

2 个答案:

答案 0 :(得分:2)

首先,您需要使用与修补相同的名称来创建foo,即

class SystemUnderTest(object):

    def my_func(self):
        foo = mypackage.ClassWithComplexInit()
        return foo.get_value()

其次,您需要配置正确的模拟对象。您正在配置未绑定方法ClassWithComplexInit.get_value,但您需要配置ClassWithComplexInit.return_value.get_value,这是Mock对象,实际上将使用foo.get_value()进行调用。

@mock.patch('mypackage.ClassWithComplexInit')
def test_with_patched_class(self, mockClass):
    mockClass.return_value.get_value.return_value = 'test value'
    sut = SystemUnderTest()
    result = sut.my_func()  # seems to not execute ClassWithComplexInit.__init__()
    self.assertEqual('test value', result)  # still fails

答案 1 :(得分:-1)

为什么不将它子化为测试并覆盖init?

class testClassWithComplexInit(ClassWithComplexInit):
    def __init__(self):
        pass

ClassWithComplexInit = testClassWithComplexInit

现在,ClassWithComplexInit().get_value()返回'My value'而非提出异常。