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:

以下にいくつかの提案を示します。

  • Spreadsheet クラスは、ファイル名ではなく、ファイルのようなオブジェクトを取ります。これにより、より一般的になり、他のストリームベースのオブジェクトで使用できるようになります。これがあれば、偽のファイルを作成する必要はなく、StringIOテスト用のインスタンスを作成するだけで済みます。
  • を使用することに設定している場合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

NamedTemporaryFilewithステートメントでそのまま使用できる、すでに開かれているファイルのようなオブジェクトを返します。呼び出す必要はありませんopen

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