I am trying to unit test a piece of code:
def _parse_results(self, file_name):
results_file = open(file_name)
results_data = list(csv.reader(results_file))
index = len(results_data[1])-1
results_file.close()
return float(results_data[1][index])
by using mock_open like so:
@mock.patch('path.open', mock.mock_open(read_data='test, test2, test3, test4'))
def test_parse_results(self):
cut = my_class(emulate=True)
self.assertEqual(VAL, cut._parse_results('file'))
The problem I am running into is that I do not get any data when running csv.reader. If I run results_file.readlines() I get 'test, test2, test3, test4' which means that mock_open is working properly. But when I run csv.reader(results_file) I lose all the data.
This is because mock_open
doesn't implement every feature that a file has, and notably not some of the ones that csv
needs.
mock_open
implements the methods read()
, readline()
and readlines()
, and works both as a function and when called as a context manager (https://docs.python.org/3/library/unittest.mock.html#mock-open), whereas csv.reader
works with…
any object which supports the iterator protocol and returns a string each time its
__next__()
method is called — file objects and list objects are both suitable— https://docs.python.org/3/library/csv.html#csv.reader
Note that mock_open
doesn't implement the __next__()
method, and doesn't raise StopIteration
when the end is reached, so it won't work with csv.reader
.
The solution, as @Emily points out in her answer, is to turn the file into a list of its lines. This is possible because mock_open
implements readlines()
, and the resulting list is suitable for reading into csv.reader
as the documentation says.
This really got me too, and was a nightmare to pinpoint. To use your example code, this works
results_data = list(csv.reader(results_file.read()))
and this works
results_data = list(csv.reader(results_file.readlines()))
but this doesn't work
results_data = list(csv.reader(results_file))
using Python 3.4.
It seems counter to the documented interface of csv.reader
so maybe an expert can elaborate on why.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With