Preferred way of patching multiple methods in Python unit test -
i need patch 3 methods (_send_reply
, _reset_watchdog
, _handle_set_watchdog
) mock methods before testing call fourth method (_handle_command
) in unit test of mine.
from looking @ documentation mock package, there's few ways go it:
with patch.multiple
decorator
@patch.multiple(mbg120simulator, _send_reply=default, _reset_watchdog=default, _handle_set_watchdog=default, autospec=true) def test_handle_command_too_short_v1(self, _send_reply, _reset_watchdog, _handle_set_watchdog): simulator = mbg120simulator() simulator._handle_command('xa99') _send_reply.assert_called_once_with(simulator, 'x?') self.assertfalse(_reset_watchdog.called) self.assertfalse(_handle_set_watchdog.called) simulator.stop()
with patch.multiple
context manager
def test_handle_command_too_short_v2(self): simulator = mbg120simulator() patch.multiple(simulator, _send_reply=default, _reset_watchdog=default, _handle_set_watchdog=default, autospec=true) mocks: simulator._handle_command('xa99') mocks['_send_reply'].assert_called_once_with('x?') self.assertfalse(mocks['_reset_watchdog'].called) self.assertfalse(mocks['_handle_set_watchdog'].called) simulator.stop()
with multiple patch.object
decoratorations
@patch.object(mbg120simulator, '_send_reply', autospec=true) @patch.object(mbg120simulator, '_reset_watchdog', autospec=true) @patch.object(mbg120simulator, '_handle_set_watchdog', autospec=true) def test_handle_command_too_short_v3(self, _handle_set_watchdog_mock, _reset_watchdog_mock, _send_reply_mock): simulator = mbg120simulator() simulator._handle_command('xa99') _send_reply_mock.assert_called_once_with(simulator, 'x?') self.assertfalse(_reset_watchdog_mock.called) self.assertfalse(_handle_set_watchdog_mock.called) simulator.stop()
manually replacing methods using create_autospec
def test_handle_command_too_short_v4(self): simulator = mbg120simulator() # mock methods. simulator._send_reply = create_autospec(simulator._send_reply) simulator._reset_watchdog = create_autospec(simulator._reset_watchdog) simulator._handle_set_watchdog = create_autospec(simulator._handle_set_watchdog) # exercise. simulator._handle_command('xa99') # check. simulator._send_reply.assert_called_once_with('x?') self.assertfalse(simulator._reset_watchdog.called) self.assertfalse(simulator._handle_set_watchdog.called)
personally think last 1 clearest read, , not result in horribly long lines if number of mocked methods grow. avoids having pass in simulator
first (self
) argument assert_called_once_with
.
but don't find of them particularly nice. multiple patch.object
approach, requires careful matching of parameter order nested decorations.
is there approach i've missed, or way make more readable? do when need patch multiple methods on instance/class under test?
no didn't have missed different proposed.
about readability taste decorator way because remove mocking stuff test body... taste.
you right: if patch static instance of method autospec=true
must use self in assert_called_*
family check methods. case small class because know object need patch , don't need other context patch test method.
you need patch object use test: in tests cannot have instance patch before doing call , in these cases create_autospec
cannot used: can patch static instance of methods instead.
if bothered passing instance assert_called_*
methods consider use any
break dependency. wrote hundreds of test , never had problem arguments order.
my standard approach @ test is
@patch('mbgmodule.mbg120simulator._send_reply', autospec=true) @patch('mbgmodule.mbg120simulator._reset_watchdog', autospec=true) @patch('mbgmodule.mbg120simulator._handle_set_watchdog', autospec=true) def test_handle_command_too_short(self,mock_handle_set_watchdog, mock_reset_watchdog, mock_send_reply): simulator = mbg120simulator() simulator._handle_command('xa99') # can use instead simulator if don't know mock_send_reply.assert_called_once_with(simulator, 'x?') self.assertfalse(mock_reset_watchdog.called) self.assertfalse(mock_handle_set_watchdog_mock.called) simulator.stop()
- patching out of test method code
- every mock starts
mock_
prefix - i prefer use simple
patch
call , absolute path: clear , neat doing
finally: maybe create simulator
, stop setup()
, teardown()
responsibility , tests should take in account patch methods , checks.
i hope answer useful question don't have unique valid answer because readability not absolute concept , depends reader. title speaking general case, question examples specific class of problem should patch methods of object test.
[edit]
i though while question , found bother me: trying test , sense on private methods. when happen first thing should ask why? there lot chances answer because these methods should public methods of private collaborators (that not words).
in new scenario should sense on private collaborators , cannot change object. need patch static instance of other classes.
Comments
Post a Comment