Can mock.mock_open.read return different values?

Tim Golden mail at timgolden.me.uk
Mon Mar 12 04:51:32 EDT 2018


I'm contributing to a codebase which makes heavy use of mock in the test 
suite, a technique which I'm aware of but have used only rarely. In one 
situation it uses mock.mock_open(read_data="...") and then asserts again 
mock_open.return_value.read.call_count.

A code change I've made results in an increase in the call count but 
also the open() I've introduced opens the file in binary mode and does 
something with the resulting data.

Hugely simplified, the new code and unchanged test looks like this:

import os, sys
import unittest
from unittest import mock

def read_file(filename):

     #
     # This section is new
     #
     with open(filename, "rb") as f:
         text = f.read()
         if text.startswith(b"#"):
             pass

     with open(filename) as f:
         text = f.read()
         if text.startswith("#"):
             pass

     return text

class TestS(unittest.TestCase):

     def test_read_file(self):
         mock_open = mock.mock_open(read_data="abc")
         with mock.patch('builtins.open', mock_open):
             data = read_file("abc")
         assert mock_open.return_value.read.call_count == 1

if __name__ == '__main__':
     unittest.main()


I would expect the test to fail because of the call_count change. But in 
fact it errors out because the newly-added "if test.startswith()" 
receives a string, not bytes, from the Mock's read_data functionality.

Ignore for the moment any question of changing the read_file 
implementation to assist testing. And leave aside the question of 
whether a mock_open is really a good test approach here.

Is there any way in which I can have the mock_open object return bytes 
for the first open and a string for the second? I've looked at setting a 
side_effect function against the mock_open.return_value.read Mock, but I 
can't see a way of having the function know whether it's supposed to be 
returning bytes or string.


TJG



More information about the Python-list mailing list