Reputation: 10299
I want to mock a hierarchy of classes. For example:
class Base(object):
def one(self):
return 'one'
def two(self):
return 'two'
class Derived(Base):
def three(self):
return 'three'
It is straightforward to define basic mocks:
from mock import Mock
def BaseMock():
mock = Mock()
mock.one.return_value = 'uno'
mock.two.return_value = 'dos'
return mock
def DerivedMock():
mock = BaseMock()
mock.three.return_value = 'tres'
return mock
The above works, but it is incomplete. I want to use the Mock
arguments spec
and name
. I can specify them as usual in BaseMock
, but in DerivedMock
, I have to modify private Mock
attributes, which is bad form.
Is there a proper way to mock a hierarchy of classes complete with spec
and name
?
Upvotes: 3
Views: 516
Reputation: 10299
To mock a class hierarchy, define the base class mock as usual:
from mock import Mock
def BaseMock():
mock = Mock(spec=Base, name='BaseMock')
mock.one.return_value = 'uno'
mock.two.return_value = 'dos'
return mock
In the derived mock, instantiate the base mock and (odious as it is) modify the Mock private attributes related spec
and name
:
def DerivedMock():
mock = BaseMock()
# Set Mock private attributes to Derived
mock._mock_methods.extend(dir(Derived))
mock._mock_name = 'DerivedMock'
mock._spec_class = Derived
mock.three.return_value = 'tres'
# Defining DerivedMock.four would cause a spec error
# mock.four.return_value = 'quatro'
return mock
Now mock DerivedMock looks like class Derived, except that the return values are different:
d = DerivedMock()
assert isinstance(d, Derived)
assert repr(d).startswith("<Mock name='DerivedeMock' spec='Derived'")
assert d.one() == 'uno'
assert d.two() == 'dos'
assert d.three() == 'tres'
Upvotes: 1