Pikzie (unittesting extention module)

Pikzie

Pythonのユニットテスト用モジュールとしては、 標準モジュールの unittest モジュール、拡張モジュールの py.testnose 等が有名です。

もうひとつ、日本語の記事をあまり見かけないのですが、 Pikzie ( Pikzie PyPI ) [1] という ユニットテスト用モジュールがあります。 テスト失敗時の出力結果の視認性を重視しているようで、 実際の使用感として、カラー表示と出力結果が見やすい点がかなり良いと感じました。 [2]

インストール

pipで簡単にインストールできます。

$ pip install Pikzie

特徴

開発者の方(?)のBlogに unittest/nose/py.test等と比較しながら 特徴をまとめており、そのページが参考になります。

Pikzie 0.9.2リリース - ククログ(2008-06-27)

たしかにテストは失敗することの方が多く、そのテスト結果出力は 生産性にも大きく関わっているような気がします。開発者の方の目のつけどころが良いですね。 (実は、 pyunitdiffpyrg も出発点はPikzieで、そこからRubyのZenTestとかを見て作ってみました。)

バグ?

たまたまMacの環境変数$TERMが"xterm-color"になっていたので気づいたのですが、 カラー表示できない(しない)場合にエラー終了する問題(?)を見つけました。

$ cat pik.py
import pikzie

class TestPik(pikzie.TestCase):

    def test_one(self):
        self.assert_equal(1, None)
$ python pik.py
F

1) Failure: TestPik.test_one: self.assert_equal(1, None)
pik.py:6: self.assert_equal(1, None)
expected: <1>
 but was: <None>

Finished in 0.002 seconds

1 test(s), 0 assertion(s), 1 failure(s), 0 error(s), 0 pending(s), 0 notification(s)
$ export TERM="xtermz"
$ python pik.py
FPE..

1) Failure: FileCheckTest.test_invalhotshot: self.assert_equal(self.p2h.check_hotshot("htt-version"), True)
piktest.py:14: self.assert_equal(self.p2h.check_hotshot("htt-version"), True)
Error in atexit._run_exitfuncs:
Traceback (most recent call last):
  File "/usr/lib/python2.5/atexit.py", line 24, in _run_exitfuncs
    func(*targs, **kargs)
  File "/usr/lib/python2.5/site-packages/Pikzie-0.9.3-py2.5.egg/pikzie/tester.py", line 81, in auto_test_run
    sys.exit(Tester(target_modules=['__main__']).run())
  File "/usr/lib/python2.5/site-packages/Pikzie-0.9.3-py2.5.egg/pikzie/tester.py", line 44, in run
    context = runner.run(test, listeners)
  File "/usr/lib/python2.5/site-packages/Pikzie-0.9.3-py2.5.egg/pikzie/ui/console.py", line 88, in run
    test.run(context)
  File "/usr/lib/python2.5/site-packages/Pikzie-0.9.3-py2.5.egg/pikzie/core.py", line 51, in run
    context.on_finish_test_suite(self)
  File "/usr/lib/python2.5/site-packages/Pikzie-0.9.3-py2.5.egg/pikzie/core.py", line 578, in on_finish_test_suite
    self._notify("finish_test_suite", test_suite)
  File "/usr/lib/python2.5/site-packages/Pikzie-0.9.3-py2.5.egg/pikzie/core.py", line 626, in _notify
    getattr(listener, callback_name)(self, *args)
  File "/usr/lib/python2.5/site-packages/Pikzie-0.9.3-py2.5.egg/pikzie/ui/console.py", line 100, in on_finish_test_suite
    self._print_faults(context)
  File "/usr/lib/python2.5/site-packages/Pikzie-0.9.3-py2.5.egg/pikzie/ui/console.py", line 219, in _print_faults
    self._writeln(detail, self._fault_color(fault))
  File "/usr/lib/python2.5/site-packages/Pikzie-0.9.3-py2.5.egg/pikzie/ui/console.py", line 201, in _writeln
    self._write(arg, color, level)
  File "/usr/lib/python2.5/site-packages/Pikzie-0.9.3-py2.5.egg/pikzie/ui/console.py", line 193, in _write
    self.output.write(arg)
TypeError: argument 1 must be string or read-only character buffer, not AssertionFailure
Error in sys.exitfunc:
Traceback (most recent call last):
  File "/usr/lib/python2.5/atexit.py", line 24, in _run_exitfuncs
    func(*targs, **kargs)
  File "/usr/lib/python2.5/site-packages/Pikzie-0.9.3-py2.5.egg/pikzie/tester.py", line 81, in auto_test_run
    sys.exit(Tester(target_modules=['__main__']).run())
  File "/usr/lib/python2.5/site-packages/Pikzie-0.9.3-py2.5.egg/pikzie/tester.py", line 44, in run
    context = runner.run(test, listeners)
  File "/usr/lib/python2.5/site-packages/Pikzie-0.9.3-py2.5.egg/pikzie/ui/console.py", line 88, in run
    test.run(context)
  File "/usr/lib/python2.5/site-packages/Pikzie-0.9.3-py2.5.egg/pikzie/core.py", line 51, in run
    context.on_finish_test_suite(self)
  File "/usr/lib/python2.5/site-packages/Pikzie-0.9.3-py2.5.egg/pikzie/core.py", line 578, in on_finish_test_suite
    self._notify("finish_test_suite", test_suite)
  File "/usr/lib/python2.5/site-packages/Pikzie-0.9.3-py2.5.egg/pikzie/core.py", line 626, in _notify
    getattr(listener, callback_name)(self, *args)
  File "/usr/lib/python2.5/site-packages/Pikzie-0.9.3-py2.5.egg/pikzie/ui/console.py", line 100, in on_finish_test_suite
    self._print_faults(context)
  File "/usr/lib/python2.5/site-packages/Pikzie-0.9.3-py2.5.egg/pikzie/ui/console.py", line 219, in _print_faults
    self._writeln(detail, self._fault_color(fault))
  File "/usr/lib/python2.5/site-packages/Pikzie-0.9.3-py2.5.egg/pikzie/ui/console.py", line 201, in _writeln
    self._write(arg, color, level)
  File "/usr/lib/python2.5/site-packages/Pikzie-0.9.3-py2.5.egg/pikzie/ui/console.py", line 193, in _write
    self.output.write(arg)
TypeError: argument 1 must be string or read-only character buffer, not AssertionFailure

カラー表示時のみ文字列にエスケープ(?)しているので、 <type 'None'>とかをそのまま放り込んだ場合にエラー終了しているのではないでしょうか。 文字列に変換してあげれば大丈夫なような気がします。

pikzie/ui/console.py

186     def _write(self, arg, color=None, level=VERBOSE_LEVEL_NORMAL):
187         if self.verbose_level < level:
188             return
189         if self.use_color and color:
190             arg = "%s%s%s" % (color.escape_sequence,
191                               arg,
192                               self.reset_color.escape_sequence)
193         self.output.write(arg)
194         self.output.flush()
--- pikzie/ui/console.py.org    2009-02-22 19:47:01.000000000 +0900
+++ pikzie/ui/console.py    2009-03-04 10:49:43.000000000 +0900
@@ -190,6 +190,8 @@
             arg = "%s%s%s" % (color.escape_sequence,
                               arg,
                               self.reset_color.escape_sequence)
+        else:
+            arg = "%s" % (arg)
         self.output.write(arg)
         self.output.flush()

最後に

テストの重要性は教科書に書いてあります。 すこしずつでもユニットテストを増やして、繰り返しテストを走らせて バグを一つでもなくすようにしたいですね。 その繰り返しの作業が少しでも楽になるように、ツール類を一度見直すのも 悪くないと思います。 Pikzieもその選択肢の中に入れてみてはどうでしょうか?

ではまた。

footnote

[1]2009/03/04時点での最新バージョンは0.9.3です。
[2]py.testはPy3Kに対応しないことが決まっていたはず(どこ情報か忘れた...)。 noseは使ったことがないので一度は使ってみたいところ。