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
--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to