I have this unit test where I want to ensure my Django custom management job is writing specific messages to its log.
from unittest.mock import Mock, patch
...
@override_settings(HR_SYNC_DATA_DIR=f"{settings.BASE_DIR}/core/management/tests/HR_SYNC_DATA_DIR")
@patch('core.management.commands.process_hr_changes.log')
@patch('core.management.commands.process_hr_changes.requests.get')
def test_sync_users2(self, mock_get, mock_log):
#
# Load our Mock data
#
test_data_dir = f"{settings.BASE_DIR}/core/management/tests/TEST_DATA_DIR"
get_mocks = []
for filename in glob.glob(path.join(test_data_dir, 'test-data-hrdata_underrun_page_*.json')):
with open(filename, "r") as infile:
mock_response = Mock(ok=True)
mock_response.json.return_value = json.load(infile)
mock_response.status_code = status.HTTP_200_OK
get_mocks.append(mock_response)
mock_get.side_effect = get_mocks
with self.assertRaises(CommandError) as context:
call_command('process_hr_changes')
print(context.exception)
self.assertEqual('percent change is -0.125 and delta_pct is 0.1. Lifecycle is dev.', context.exception.args[0])
mock = Mock(return_value=None)
info_calls = [
mock.call('rehires = 0 new hires = 0 terminations = 5.'),
mock.call('process_hr_changes args are: delta_pct 0.1 how_many_hours_back 24 dry_run False debug is False verbose is False'),
mock.call('test: startup'),
mock.call('Removing directory /apps/core/management/tests/HR_SYNC_DATA_DIR.'),
mock.call('Creating directory /apps/core/management/tests/HR_SYNC_DATA_DIR.'),
mock.call('percent change is -0.125 and delta_pct is 0.1.'),
]
for mock_call in mock_log.info.mock_calls:
print(mock_call)
mock_log.info.assert_has_calls(info_calls, any_order=True)
When I run this test it fails on the mock_log.info.assert_has_calls(info_calls, any_order=True)
statement with this message:
AssertionError: (<MagicMock name='log.call()' id='140711932625744'>, <MagicMock name='log.call()' id='140711932625744'>, <MagicMock name='log.call()' id='140711932625744'>, <MagicMock name='log.call()' id='140711932625744'>, <MagicMock name='log.call()' id='140711932625744'>, <MagicMock name='log.call()' id='140711932625744'>) not all found in call list
I also see this output from my print statement:
call('process_hr_changes args are: delta_pct 0.1 how_many_hours_back 24 dry_run False debug is False verbose is False')
call('test: startup')
call('Removing directory /apps/core/management/tests/HR_SYNC_DATA_DIR.')
call('Creating directory /apps/core/management/tests/HR_SYNC_DATA_DIR.')
call('rehires = 0 new hires = 0 terminations = 5.')
call('percent change is -0.125 and delta_pct is 0.1.')
What am I doing wrong?
Thanks
UPDATE:
I had to change my code to this:
from unittest.mock import Mock, patch, call # need to import call.
...
info_calls = [
call('rehires = 0 new hires = 0 terminations = 5.'),
call('process_hr_changes args are: delta_pct 0.1 how_many_hours_back 24 dry_run False debug is False verbose is False'),
call('test: startup'),
call('Removing directory /apps/core/management/tests/HR_SYNC_DATA_DIR.'),
call('Creating directory /apps/core/management/tests/HR_SYNC_DATA_DIR.'),
call('percent change is -0.125 and delta_pct is 0.1.'),
]
mock_log.info.assert_has_calls(info_calls, any_order=True)
You are passing the result of Mock.call
to assert_has_calls
. But, assert_has_calls
expects a top-levelcall
object.
Note, after reading the docs I concur this is not overly clear. Here's the docs for assert_has_calls
:
assert the mock has been called with the specified calls. The mock_calls list is checked for the calls.
If any_order is false then the calls must be sequential. There can be extra calls before or after the specified calls.
If any_order is true then the calls can be in any order, but they must all appear in mock_calls.
mock = Mock(return_value=None) mock(1) mock(2) mock(3) mock(4) calls = [call(2), call(3)] mock.assert_has_calls(calls) calls = [call(4), call(2), call(3)] mock.assert_has_calls(calls, any_order=True)
It's not clear where the call
object comes from in that example. I can see the confusion.
It's only when you see thecall
documentation that it gets a bit clearer (emphasis mine):
call() is a helper object for making simpler assertions, for comparing with call_args, call_args_list, mock_calls and method_calls. call() can also be used with assert_has_calls() .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.