テストを自動化したくてModipyd使ってみた
さっきインストールしたModipydを実際に使ってみた。
チュートリアルに従って動作させる。
Modipyd の自動テストツールを使ってみよう — Modipyd
テストコード用意
テスト用ディレクトリ「C:\pytest\」作成。
チュートリアルにあった2つのファイルを作成。
- widget.py
import os import sys class Widget(object): """ Widget is a User Interface (UI) component object. A widget object claims a rectagular region of its content, is responsible for all drawing within that region. """ def __init__(self, name, width=50, height=50): self.name = name self.width = width self.height = height def size(self): return (self.width, self.height)
- test_widget.py
import unittest from widget import Widget class SimpleWidgetTestCase(unittest.TestCase): def test_init(self): widget = Widget('The widget', 10, 10) self.failUnless(widget.size() == (10, 10), 'incorrect size') def test_default_size(self): widget = Widget('The widget') self.failUnless(widget.size() == (50, 50), 'incorrect default size') if __name__ == '__main__': unittest.main()
ちゃんとある。
C:\pytest>dir 2010/03/01 19:23 <DIR> . 2010/03/01 19:23 <DIR> .. 2010/03/01 19:16 493 test_widget.py 2010/03/01 19:15 444 widget.py
テスト実行
C:\pytest>pyautotest -v 'pyautotest' は、内部コマンドまたは外部コマンド、 操作可能なプログラムまたはバッチ ファイルとして認識されていません。
あれーパス通ってないのかな。めんどいから直接動かす。
C:\pytest>C:\Python25\Lib\site-packages\Modipyd-1.0-py2.5.egg\modipyd\tools\autotest.py -v [INFO] Loading plugin: <class 'modipyd.application.plugins.Autotest'> [INFO] Loading BytecodeProcesser 'modipyd.bytecode.ImportProcessor' [INFO] Loading BytecodeProcesser 'modipyd.bytecode.ClassDefinitionProcessor' [INFO] Monitoring: test_widget: C:\pytest\test_widget.py Dependencies: ['widget'] Reverse: [] widget: C:\pytest\widget.py Dependencies: [] Reverse: ['test_widget']
よし動いた。乱暴なやり方かもしれないけど動いた感動の方が勝ってる。
このままチュートリアルを進める。
やっとチュートリアル
上記 widget.py を少し変更する。
# 変更前 def __init__(self, name, width=50, height=50): self.name = name self.width = width self.height = height # 変更後 def __init__(self, name, width=50, height=50): self.name = name self.width, self.height = width, height
すると、保存した途端にテストを実行して結果を吐き出してくれた。これは楽ですねー
[INFO] Reload module descriptor 'widget' at C:\pytest\widget.py [INFO] Modified: widget: C:\pytest\widget.py Dependencies: [] Reverse: ['test_widget'] [INFO] -> Affected: widget [INFO] -> Affected: test_widget [INFO] Running UnitTests: test_widget .. ---------------------------------------------------------------------- Ran 2 tests in 0.000s OK
ツールをまともに使った経験がないけど、テストで発生したエラーがとても分かりやすくて良いと思った。
テストでエラーを発生させ、修正する
テストを追加
- test_widget.py
import unittest from widget import Widget class SimpleWidgetTestCase(unittest.TestCase): def test_init(self): widget = Widget('The widget', 10, 10) self.failUnless(widget.size() == (10, 10), 'incorrect size') def test_default_size(self): widget = Widget('The widget') self.failUnless(widget.size() == (50, 50), 'incorrect default size') class WidgetResizeTestCase(unittest.TestCase): def test_resize(self): widget = Widget('The widget', 15, 30) self.failUnless(widget.size() == (15, 30)) widget.resize(45, 50) self.failUnless(widget.size() == (45, 50)) if __name__ == '__main__': unittest.main()
エラーが発生。
[INFO] Reload module descriptor 'widget' at C:\pytest\widget.py [INFO] Modified: widget: C:\pytest\widget.py Dependencies: [] Reverse: ['test_widget'] [INFO] -> Affected: widget [INFO] -> Affected: test_widget [INFO] Running UnitTests: test_widget ..E ====================================================================== ERROR: test_resize (test_widget.WidgetResizeTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "test_widget.py", line 21, in test_resize widget.resize(45, 50) AttributeError: 'Widget' object has no attribute 'resize' ---------------------------------------------------------------------- Ran 3 tests in 0.001s FAILED (errors=1)
widget.py に resize() を実装。
- widget.py
import os import sys class Widget(object): """ Widget is a User Interface (UI) component object. A widget object claims a rectagular region of its content, is responsible for all drawing within that region. """ def __init__(self, name, width=50, height=50): self.name = name self.width, self.height = width, height def size(self): return (self.width, self.height) def resize(self): self.width, self.height = width, height
間違えてた。
[INFO] Reload module descriptor 'widget' at C:\pytest\widget.py [INFO] Modified: widget: C:\pytest\widget.py Dependencies: [] Reverse: ['test_widget'] [INFO] -> Affected: widget [INFO] -> Affected: test_widget [INFO] Running UnitTests: test_widget ..E ====================================================================== ERROR: test_resize (test_widget.WidgetResizeTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "test_widget.py", line 21, in test_resize widget.resize(45, 50) TypeError: resize() takes exactly 1 argument (3 given) ---------------------------------------------------------------------- Ran 3 tests in 0.001s FAILED (errors=1)
今度こそ修正。
- widget.py
import os import sys class Widget(object): """ Widget is a User Interface (UI) component object. A widget object claims a rectagular region of its content, is responsible for all drawing within that region. """ def __init__(self, name, width=50, height=50): self.name = name self.width, self.height = width, height def size(self): return (self.width, self.height) def resize(self, width, height): self.width, self.height = width, height
テストに通った。
[INFO] Reload module descriptor 'widget' at C:\pytest\widget.py [INFO] Modified: widget: C:\pytest\widget.py Dependencies: [] Reverse: ['test_widget'] [INFO] -> Affected: widget [INFO] -> Affected: test_widget [INFO] Running UnitTests: test_widget ... ---------------------------------------------------------------------- Ran 3 tests in 0.001s OK
自動的にテストしてくれるというのはとっても楽なことなんだと思った。
あと自身がない箇所や、自分が安心したい箇所をテストにしてクリアしていくというのはとても脳汁溢れる良い行為だと思いました。