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
What is mocking? Mocking is a process used in unit testing when the unit being tested has external dependencies. The purpose of mocking is to isolate and focus on the code being tested and not on the behavior or state of external dependencies.
mock provides a powerful mechanism for mocking objects, called patch() , which looks up an object in a given module and replaces that object with a Mock . Usually, you use patch() as a decorator or a context manager to provide a scope in which you will mock the target object.
With Mock you can mock magic methods but you have to define them. MagicMock has "default implementations of most of the magic methods.". If you don't need to test any magic methods, Mock is adequate and doesn't bring a lot of extraneous things into your tests.
What is mocking in Python? Mocking in Python means the unittest. mock library is being utilized to replace parts of the system with mock objects, allowing easier and more efficient unit testing than would otherwise be possible.
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
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With