Mocking two functions with patch for a unit test

mocking, nose, python, testing, unit-testing

Solution

You can simplify your test by using the patch decorator and nesting them like so (they are `MagicMock` objects by default):

from unittest.mock import patch

@patch('cPickle.dump')
@patch('__builtin__.open')
def test_write_out(mock_open, mock_pickle):
    path = '~/collection'
    f = mock_open.return_value
    f.method.return_value = path
    
    write_out(path, 'data')
    
    mock_open.assert_called_once_with('~/collection', 'wb')
    mock_pickle.assert_called_once_with('data', f)
    f.close.assert_any_call()

Calls to a `MagicMock` instance return a new `MagicMock` instance, so you can check that the returned value was called just like any other mocked object. In this case `f` is a `MagicMock` named `'open()'` (try printing `f`).

Problem

I have a function I want to unit test contains calls two other functions. I am unsure how can I mock both functions at the same time properly using patch. I have provided an example of what I mean below. When I run nosetests, the tests pass but I feel that there must be a cleaner way to do this and I do not really Understand the piece regarding f.close()... The directory structure looks like this: ``` program/ program/ data.py tests/ data_test.py ``` data.py: ``` import cPickle def write_out(file_path, data): f = open(file_path, 'wb') cPickle.dump(data, f) f.close() ``` data_test.py: ``` from mock import MagicMock, patch def test_write_out(): path = '~/collection' mock_open = MagicMock() mock_pickle = MagicMock() f_mock = MagicMock() with patch('__builtin__.open', mock_open): f = mock_open.return_value f.method.return_value = path with patch('cPickle.dump', mock_pickle): write_out(path, 'data') mock_open.assert_called_once_with('~/collection', 'wb') f.close.assert_any_call() mock_pickle.assert_called_once_with('data', f) ``` Results: ``` $ nosetests . ---------------------------------------------------------------------- Ran 1 test in 0.008s OK ```

Original source