Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mock_open CSV file not getting any data

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.

like image 917
draB1 Avatar asked Jun 16 '16 00:06

draB1


2 Answers

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.

like image 81
nimasmi Avatar answered Sep 28 '22 12:09

nimasmi


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.

like image 30
wemily Avatar answered Sep 28 '22 13:09

wemily