7

我有一个__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'>

上面的第二种方法是我从这个类似的问答中得到的,但它也不起作用。它似乎没有运行该__init__函数,但我的断言失败了,因为结果最终是一个模拟实例,而不是我的值。

我还尝试patch在函数中配置一个实例setUp,使用文档建议start的andstop函数。

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__由我的测试代码实例化的复杂类?理想情况下,我想要一个适用于 TestCase 类中的许多单元测试的解决方案(例如,不需要patch每个测试)。

我正在使用 Python 版本2.7.6

4

1 回答 1

4

首先,您需要使用与您正在修补的名称相同的名称来创建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
于 2014-11-05T21:28:52.543 回答