File Iteration With python-mock
by Justin Michalicek on Feb. 27, 2014, 2:06 a.m. UTCI came across a unit test situation recently where I did not want to litter my project with test files for reading. I did some looking and python-mock has a way to mock open, but there are a couple of things to watch out for. What is documented there doesn't quite work right off the bat. The documentation shows this:
with patch('__main__.open', mock_open(read_data='bibble'), create=True) as m: with open('foo') as h: result = h.read()
Simple enough. Except right away, that __main__.open actually needs to be __builtin__.open, at least on Python 2.7. After that calling read() works fine, but line by line iteration in the usual manner does not.
with patch('__main__.open', mock_open(read_data='bibble'), create=True) as m: with open('foo') as h: for line in h: print line
That just prints nothing. Eventually, I realized that __iter__ is not being set and so went and dug through the mock source. After seeing what is really being returned, I came up with this solution, which seems to have done the trick.
text_file_data = '\n'.join(["a line here", "the second line", "another line in the file"]) with patch('__builtin__.open', mock_open(read_data=text_file_data), create=True) as m: # mock_open doesn't properly handle iterating over the open file with for line in file: # but if we set the return value like this, it works. m.return_value.__iter__.return_value = text_file_data.splitlines() with open('filename', 'rU') as f: for line in f: print line
Basically, get the mock object, then on its return_value set the __iter__ to an iterable.