So I'm writing a test for this class (edited to be more clear):
class SpreadSheet(object):
'''awesome docstring'''
def __init__(self, filename):
self.filename = filename
self.table = []
self.headers = []
with open(self.filename) as csvfile:
filereader = reader(csvfile, delimiter=',')
for row in filereader:
self.table.append(row)
def create_headers(self, populations):
...code...
def lookup_header(self, ltr):
...code...
def write_header(self, targetfile):
...code...
that so far looks like this:
class TestSpreadSheet(unittest.TestCase):
@contextmanager
def make_fake_csv(self, data):
self.fake_namefile = tempfile.NamedTemporaryFile(delete=False)
with open(self.fake_namefile, 'w') as fake_csv:
fake_writer = csv.writer(fake_csv)
fake_writer.writerows(data)
yield self.fake_namefile.name
os.unlink(self.fake_namefile.name)
def setUp(self):
self.headers = []
self.table = [
['Col1', 'Col2', 'Col3', 'Col4', 'Col5', 'Col6', 'Col7', 'Col8'],
['val1', 'val2', 'val3', 'val4', 'val5', 'val6', 'val7', 'val8'],
['val1', 'val2', 'val3', 'val4', 'val5', 'val6', 'val7', 'val8'],
['val1', 'val2', 'val3', 'val4', 'val5', 'val6', 'val7', 'val8']]
def test___init__(self):
with self.make_fake_csv(self.table) as temp_csv:
spread_sheet = SpreadSheet(temp_csv)
self.assertEqual(
self.table, spread_sheet.table)
...tests for other functions...
And I get this error:
in make_fake_csv
with open(self.fake_namefile, 'w') as fake_csv:
TypeError: coercing to Unicode: need string or buffer, instance found
I've scoured many other topics like this that point to the use of tempfile
to make a named object or something that can actually be called using with open...
. And while I did actually get that to work, my issues was when I tried to use the csv
package to format my self.table
for me into a csv formatted raw "string" (like the raw input of a csv file in other words).
Any pointers on how I can test this differently or make the current code work? Again I'm trying to:
figure out how to use csv
to do all the formatting heavy-lifting to load up a fake csv file from my self.table
so that I don't have to make a huge string formatting expression
make sure that the fake file works with with open
as used in my original class SpreadSheet
when the test is run
can be used further to run the test of the other functions because they too need to instantiate SpreadSheet
with a file in order to perform their functions.
And as a side question, is it "leaner" to make a fake "memory" file to do things like this (this is what I'm attempting above) or is is just simpler to make an actual temporary file on the disk and load it up during testing and use a tearDown()
function to delete it?
Creating a Temporary FileThe file is created using the TemporaryFile() function. By default, the file is opened in w+b mode, that is, we can both read and write to the open file. Binary mode is used so that files can work with all types of data. This file may not have a proper visible name in the file system.
Type temp and press Enter (or click OK) to open up the folder location and see your temp files. Hold Ctrl and click individual items to select them for cleanup. If you want to delete everything in your temp folder, press Ctrl + A to select all the items.
self.fake_namefile
in your example is an instance of NamedTemporaryFile
. When you do the open()
call you need to pass a string containing the file name, not a NamedTemporaryFile
instance. The name of the temporary file is available in the name
variable.
with open(self.fake_namefile.name, 'w') as fake_csv:
Here's some suggestions:
StringIO
instance for testing.NamedTemporaryFile
, I'd suggest to use it as a context manager directly as outlined in the other answer.delete=True
option to NamedTemporaryFile
. Instead, wrap your entire test in the context manager as follows.def test_stuff(self):
with tempfile.NamedTemporaryFile() as temp_csv:
self.write_csv_test_data(temp_csv) # Create this to write to temp_csv file object.
temp_csv.flush()
temp_csv.seek(0)
spread_sheet = SpreadSheet(temp_csv.name)
# spread_sheet = SpreadSheet(temp_csv) Use this if Spreadsheet takes a file-like object
...
Update:
Here's an example using only file-like objects, there's no disk file involved.
class SpreadSheet(object):
'''awesome docstring'''
def __init__(self, fileobj):
self.table = []
self.headers = []
filereader = reader(fileobj, delimiter=',')
for row in filereader:
self.table.append(row)
...
It could then be used like this, assuming you were reading from a disk file:
with open(path) as csv_file:
spreadsheet = Spreadsheet(csv_file)
....
And during testing, you can use the StringIO module to simulate a file on disk. The test then runs with data entirely in memory so is very fast.
import StringIO
class TestSpreadSheet(unittest.TestCase):
def make_fake_csv(self, data):
"""Return a populdated fake csv file object for testing."""
fake_csv = StringIO.StringIO()
fake_writer = csv.writer(fake_csv)
fake_writer.writerows(data)
fake_csv.seek(0)
return fake_csv
....
def test___init__(self):
temp_csv = self.make_fake_csv(self.table)
spread_sheet = SpreadSheet(temp_csv)
self.assertEqual(
self.table, spread_sheet.table)
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