After reading this : How do I mock an open used in a with statement (using the Mock framework in Python)?
I'm able to mock the open function in python using :
with patch(open_name, create=True) as mock_open: mock_open.return_value = MagicMock(spec=file) m_file = mock_open.return_value.__enter__.return_value m_file.read.return_value = 'text1' diffman = Diffman() diffman.diff(path1, path2)
It works well when my tested method used one open statement. Here is my tested method :
def diff(self, a, b): with open(a, 'r') as old: with open(b, 'r') as new: oldtext = old.read() newtext = new.read()
The values of oldtext and newtext are the same ('text1' here).
I would like to have 'text1' for the oldtext and 'text2' for the newtext.
How can I do this ?
Here's a quick way of getting what you want. It cheats a little bit because the two file objects in the method under test are the same object and we're just changing the return value of the read call after each read. You can use the same technique in multiple layers if you want the file objects to be different, but it will be quite messy and it may disguise the intent of the test unnecessarily.
Replace this line:
m_file.read.return_value = 'text1'
reads = ['text1', 'text2'] m_file.read.side_effect = lambda: reads.pop(0)
Perhaps a good possible solution is just to write the code in a way that better lends itself to easily testing it. In the case of 'diff', it seems easy enough (not having much other context, admittedly) to have diff take as arguments already-opened file objects. This is likely a fairly small change to make in the code, and makes testing very easy, since you can then easily provide mock file objects to diff() when you test it, instead of trying to jump through hoops mocking two instances of the same builtin function as a context manager called within... itself... or something ;-)
import StringIO diff(a, b): oldtext = a.read() newtext = b.read() def test_diff(): a = StringIO.StringIO('text1') b = StringIO.StringIO('text2') res = diff(a, b) <some assertion here>
Would that work for your case?