使用Python模拟模块,我如何修补一个类,以便它只存储我想要存根的方法并单独留下其他属性和方法?

时间:2015-12-29 17:57:18

标签: python unit-testing mocking

我想要做的是在一个类中存取一些方法,这些方法在我测试的某些代码中间接实例化。我希望该补丁类的所有其他属性和方法能够正常运行。

这是一个显示我想要的简单案例(Python 2.7)。 (注意:在我的实际用例中,MyClass是一个在我测试的某些代码中间接实例化的类):

from mock import patch

class MyClass(object):
    def __init__(self):
        self.prop = 'prop'

    def foo(self):
        return 'foo'

    def bar(self):
        return 'bar'

    def unmocked(self):
        return 'unmocked'

patcher = patch('__main__.MyClass')
MockedClass = patcher.start()
instance = MockedClass.return_value
instance.foo.return_value = 'mocked foo!'
instance.bar.return_value = 'mocked bar!'

my_instance = MyClass()
assert my_instance.foo() == 'mocked foo!', my_instance.foo()
assert my_instance.bar() == 'mocked bar!', my_instance.bar()

# These asserts fail
assert my_instance.unmocked() == 'unmocked', my_instance.unmocked()
assert my_instance.prop == 'prop', my_instance.prop

patcher.stop()

结果:

$ python mock_test.py
Traceback (most recent call last):
  File "mock_test.py", line 27, in <module>
    assert my_instance.unmocked() == 'unmocked', my_instance.unmocked()
AssertionError: <MagicMock name='MyClass().unmocked()' id='140400215338448'>

为什么unmocked方法现在返回MagicMock个对象?我如何修补这个类,以便它只存储我想要的方法并将其他所有内容单独保留?

2 个答案:

答案 0 :(得分:4)

您应该使用patch.multiple修补课程:

import mock

patcher = mock.patch.multiple(
    '__main__.MyClass',
    foo=mock.Mock(return_value='mocked foo!'),
    bar=mock.Mock(return_value='bar')
)

使用上面的代码更新代码后,它将运行并且所有断言都会通过。这是一个完整的工作示例:

from mock import patch, Mock

class MyClass(object):
    def __init__(self):
        self.prop = 'prop'

    def foo(self):
        return 'foo'

    def bar(self):
        return 'bar'

    def unmocked(self):
        return 'unmocked'

patcher = patch.multiple('__main__.MyClass',
                         foo=Mock(return_value='mocked foo!'),
                         bar=Mock(return_value='mocked bar!'))
patcher.start()

my_instance = MyClass()
assert my_instance.foo() == 'mocked foo!', my_instance.foo()
assert my_instance.bar() == 'mocked bar!', my_instance.bar()
assert my_instance.unmocked() == 'unmocked', my_instance.unmocked()
assert my_instance.prop == 'prop', my_instance.prop

patcher.stop()

答案 1 :(得分:2)

from mock import patch

class MyClass(object):
    def __init__(self):
        self.prop = 'prop'

    def foo(self):
        return 'foo'

    def bar(self):
        return 'bar'

patcher = patch.object(MyClass,"foo",return_value='mocked foo!')
MockedClass = patcher.start()


my_instance = MyClass()
assert my_instance.foo() == 'mocked foo!', my_instance.foo()

# These asserts will fail
assert my_instance.bar() == 'bar', my_instance.bar()
assert my_instance.prop == 'prop', my_instance.prop

patcher.stop()

您可以使用method

直接模拟您想要的patch.object而不是整个班级