使用 Python 模拟模块,我如何修补 class 以便它只存根我想存根的方法而单独保留其他属性和方法?
Using the Python mock module, how can I patch a class so that it stubs only the methods I want to stub and leaves other properties and methods alone?
我想要做的是在 class 中存根几个方法,这些方法在我正在测试的某些代码中间接实例化。我希望那个补丁 class 的所有其他属性和方法都能正常运行。
这是一个简单的案例,它展示了我想要的东西 (Python 2.7)。 (注意:在我的实际用例中,MyClass 是一个 class,它在我正在测试的某些代码中间接实例化):
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
对象?我怎样才能修补这个 class 以便它只存根我想要的方法而不管其他所有东西?
您应该使用 patch.multiple
:
修补您的 class
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()
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()
您可以使用 patch.object
直接模拟您想要的 method
而不是整个 class
我想要做的是在 class 中存根几个方法,这些方法在我正在测试的某些代码中间接实例化。我希望那个补丁 class 的所有其他属性和方法都能正常运行。
这是一个简单的案例,它展示了我想要的东西 (Python 2.7)。 (注意:在我的实际用例中,MyClass 是一个 class,它在我正在测试的某些代码中间接实例化):
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
对象?我怎样才能修补这个 class 以便它只存根我想要的方法而不管其他所有东西?
您应该使用 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()
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()
您可以使用 patch.object
method
而不是整个 class