ファイル操作の練習とStringIO(2)

前回ファイルIOのテストは面倒だという話をしました。それでStringIOモジュールがfileobject(open(filepath)で生成される)をエミュレートしているので、StringIOを調べようということになったと思います。

StringIOモジュールの動作を知るには、ソースコードを読みながらunittestモジュールを使って単体テストを書けば良いでしょう。テストを、StringIOモジュールを実装し直してみると更に詳しく分かります。加えて、Pythonで文字列オブジェクトをどう扱うべきかも学べるはずです。標準ライブラリに含まれるStringIOの文字列の扱いがパフォーマンス的に不適切ということは考え難いことです。改善の余地があるにしても、初心者が気にするようなことではないと思います。

このようにモジュールを再実装する場合、自作したものがオリジナルの動作を確認する方法が欲しいものです。C言語だと面倒だと思いますが、Pythonなら簡単にできます。たとえばaModuleというモジュールがオリジナルだとして、MY_aModuleで動作をコピーしようとしているとすると

#!/usr/bin/env python2.6
import unittest
import aModule
class TestaModule(unittest.TestCase):
  MODULE = aModule
  def test_method(self):
    obj = self.MODULE.aClass()
import MY_aModule
class TestMY_aModule(TestaModule):
  MODULE = MY_aModule
if __name__ == '__main__':
  unittest.main()

のように書けば良いです。unittest.main()は定義されたTestCaseに定義されたテストメソッドを全て実行してくれます。パフォーマンスの比較ができない不満は残りますが、学習用としては十分だと思います。

では、StringIOモジュールの場合を書いてみましょう。openで生成されるfileobjectのようなモノですが、ただの文字列なのでgetvalue()というメソッドを使うと、ファイルの中身に相当する文字列を返してくれるようです。

#!/usr/bin/env python2.6
import unittest
import StringIO
class StringIOTest(unittest.TestCase):
  MODULE = StringIO
  def test_constructor_with_string(self):
    s = 'hello'
    fp = self.MODULE.StringIO(s)
    self.assertFalse(fp.closed)
    self.assertEqual('hello', fp.getvalue())
    fp.close()
if __name__ == '__main__':
  unittest.main()

このテストを実行すると、成功します。これをMY_StringIOにも実装したいと思います。テストを追加しましょう。

    self.assertEqual('hello', fp.getvalue())
    fp.close()
import MY_StringIO
class MY_StringIOTest(StringIOTest):
  MODULE = MY_StringIO
if __name__ == '__main__':
  unittest.main()

このテストをすぐに実行するとImportErrorになります。では、テストにパスするためにMY_StringIO.pyを作りましょう。

class StringIO:
  def __init__(self, inp):
    self.buf = inp
    self.closed = False
    self.len = len(inp)
  def getvalue(self):
    return self.buf
  def close(self):
    self.closed = True

これでパスします。次回は、writeメソッドを実装することにしましょう。


..

                                                                                                                                          • -

Ran 2 tests in 0.000s

OK