14

I'm trying to mock read from file. Using examples it can be done with a construction like:

with patch('__builtin__.open', mock_open(read_data='1'), create=True) as m:
    with open('foo') as h:
        result = h.read()

I wonder, is there a way to mock open function using my testcase annotation. Like:

@patch.object(__builtin__, 'open')
def test_check_status_running(self, m_open):

I don't find the correct way, because for me it works for int and doesn't work for strings:

@patch.object(__builtin__, 'open')
def test_check_status_running1(self, m_open):
    m_open = mock_open(read_data='1')
    pid = open('testfile').read().strip()
    print type(pid)                    # <class 'mock.MagicMock'>
    self.assertEqual(1, int(pid))      # Pass
    self.assertEqual('1', pid)         # Fails MismatchError: '1' != <MagicMock name='open().read()' id='39774928'>
Gwen
  • 306
  • 1
  • 2
  • 10
  • See http://stackoverflow.com/a/3268310/552793 for example of mocking file open using the @patch annotation – jlb83 Dec 11 '14 at 17:59

2 Answers2

21

You can patch the open method in many ways. I prefer to patch the builtins.open and to pass the mocked object to the test method like this:

from unittest.mock import patch, mock_open
from mymodule import method_that_read_with_open

class TestPatch(unittest.TestCase):
    @patch('builtins.open', new_callable=mock_open, read_data='1')
    def test_open_file(self, m):
        string_read = method_that_read_with_open()
        self.assertEqual(string_read, '1')
        m.assert_called_with('filename', 'r')

Note that we are passing the mock_open function without calling it!

But because you are patching the builtin method, you can also do:

class TestPatch(unittest.TestCase):
    @patch('builtins.open', mock_open(read_data='1'))
    def test_open_file(self):
        string_read = method_that_read_with_open()
        self.assertEqual(string_read, '1')
        open.assert_called_with('filename', 'r')

This two examples are basically equivalent: in the first one we are giving to the patch method a factory function that he will invoke to create the mock object, in the second one we are using an already created object as argument.

Genma
  • 1,221
  • 10
  • 7
  • 1
    Finally an example that works with Python 3.5. The mock library has changed and there's a lot of answers out there which only work for older versions :/ – Dirk Jan 04 '17 at 17:18
1

Assign a mock_open instance to the new_callable parameter:

class TestClass(unittest.TestCase):
    @mock.patch('file_tested.open', new_callable=mock.mock_open())
    def test_function(self, mock_open):
        pass
whats_done_is
  • 282
  • 1
  • 9