10

所以我正在为这个类写一个测试(编辑得更清楚):

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...

到目前为止看起来像这样:

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...

我得到这个错误:

in make_fake_csv
with open(self.fake_namefile, 'w') as fake_csv:
TypeError: coercing to Unicode: need string or buffer, instance found

我已经搜索了许多其他类似的主题,这些主题指向使用tempfile来制作命名对象或实际上可以使用with open.... 虽然我确实让它工作了,但我的问题是当我尝试使用csv包为我self.table将我的格式格式化为 csv 格式的原始“字符串”(换句话说,就像 csv 文件的原始输入)。

关于如何以不同方式进行测试或使当前代码工作的任何指示?我再次尝试:

  1. 弄清楚如何使用csv来完成所有繁重的格式化工作以从我的加载一个假的 csv 文件,self.table这样我就不必制作一个巨大的字符串格式化表达式

  2. 确保运行测试时假文件与with open我的原始课程中使用的一样SpreadSheet

  3. 可以进一步用于运行其他函数的测试,因为它们也需要SpreadSheet用文件实例化才能执行它们的功能。

作为一个附带问题,制作一个假的“内存”文件来做这样的事情是“更精简”(这是我在上面尝试的)还是只是更简单地在磁盘上制作一个实际的临时文件并加载它在测试过程中向上并使用一个tearDown()函数来删除它?

4

2 回答 2

8

self.fake_namefile在您的示例中是NamedTemporaryFile. 当您进行open()调用时,您需要传递一个包含文件名的字符串,而不是NamedTemporaryFile实例。临时文件的名称在name变量中可用。

with open(self.fake_namefile.name, 'w') as fake_csv:

这里有一些建议:

  • 让您的电子表格类采用类似文件的对象而不是文件名。这使它更通用,并允许它与其他基于流的对象一起使用。如果你有这个,就不需要创建一个假文件,你可以简单地构建一个StringIO实例进行测试。
  • 如果您打算使用 a NamedTemporaryFile,我建议您直接将其用作上下文管理器,如另一个答案中所述。
  • 您不必使用该delete=True选项来NamedTemporaryFile. 相反,将整个测试包装在上下文管理器中,如下所示。
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
        ...

更新:

这是一个仅使用类文件对象的示例,不涉及磁盘文件。

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)
    ...

然后可以像这样使用它,假设您正在从磁盘文件中读取:

with open(path) as csv_file:
    spreadsheet = Spreadsheet(csv_file)
    ....

并且在测试过程中,您可以使用 StringIO 模块来模拟磁盘上的文件。然后测试完全在内存中运行数据,因此非常快。

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)
于 2013-11-11T07:31:07.590 回答
2

NamedTemporaryFile返回一个已经打开的类文件对象,可以按原样在with语句中使用,无需调用open

    self.fake_namefile = tempfile.NamedTemporaryFile(delete=False)
    with self.fake_namefile as fake_csv:
于 2013-11-11T07:00:43.747 回答