テスト駆動開発支援のtest-case-mode.elを使ってみた

今更感はあるが、最近テスト駆動開発支援Emacs Lispのtest-case-mode.elが発表された。

http://nschum.de/src/emacs/test-case-mode/

M-x auto-install-batch test-case-mode でインストール。

こんな感じ。

  • テスト成功のグリーン、失敗のレッドなどの信号をモードラインに表示させる
  • バッファが変更されたら信号も対応して変わる
  • テストを実行して、失敗したら、その行へM-x next-errorとM-x previous-errorで飛べる
  • assert関数群に色がつく
  • JUnit, CxxTest, CppUnit, Python(PyUnit), Ruby (test/unit)に対応
  • テストコードを自動判別して、テストコードならばtest-unit-modeを有効にする

設定

以下の.emacsに加える。

(require 'test-case-mode)
(add-hook 'find-file-hook 'enable-test-case-mode-if-test)

さらに、コンパイル後に自動実行したいなら、以下も加える

(add-hook 'compilation-finish-functions 'test-case-compilation-finish-run-all)

使い方

テストコードを始めて書くならばM-x test-case-modeで有効にする。無効にするときも同様。
有効にしたら、モードラインに「Test::Unit」等、どのテスティングフレームワークが有効になっているのかがわかるようになる。
そして、M-x test-case-runでテスト実行。


成功時は何もでてこない。
http://www.rubyist.net/~rubikitch/archive/test-case-mode-green.png

失敗したら信号が赤に変わり、結果が出てくる。
http://www.rubyist.net/~rubikitch/archive/test-case-mode-red.png

感想

同じ言語でもテスティングフレームワークはいろいろあるので、複数のテスティングフレームワークに対応してほしいところ。RubyだったらTest::Unit以外にもRSpecやexpectationsなど。
コードを読んだところ、新たなテスティングフレームワークに対応させるのは難しくなさそう。

こんな感じにtest-case-backendsで、対応バックエンド(テスティングフレームワーク)のリストがあって、順番に呼び出していって、検出されたものが有効になる。

(defcustom test-case-backends
  '(test-case-junit-backend test-case-ruby-backend test-case-cxxtest-backend
    test-case-cppunit-backend test-case-python-backend))

(defun test-case-detect-backend ()
  (when buffer-file-name
    (dolist (backend test-case-backends)
      (when (funcall backend 'supported)
        (setq test-case-backend backend
              test-case-lighter (concat " " (test-case-call-backend 'name)))
        (return t)))))

で、RubyのTest::Unitの部分はこんな感じになっている。

(defcustom test-case-ruby-executable 〜)

(defcustom test-case-ruby-arguments 〜)


(defvar test-case-ruby-font-lock-keywords 〜)

(defvar test-case-ruby-failure-pattern 〜)

(defun test-case-ruby-backend (command)
  "Ruby Test::Unit back-end for `test-case-mode'."
  (case command
    ('name "Test::Unit")
    ('supported (and (derived-mode-p 'ruby-mode)
                     (test-case-grep "require\s+['\"]test/unit['\"]")))
    ('command (concat test-case-ruby-executable " "
                      test-case-ruby-arguments " " buffer-file-name))
    ('save t)
    ('failure-pattern test-case-ruby-failure-pattern)
    ('font-lock-keywords test-case-ruby-font-lock-keywords)))

だから、test-case-ruby-backend関数*1をぱくって、test-case-backendに追加すれば対応できると思う。

あと、#!を検出してくれないのも問題なので作者にメール送っておいた。

*1:それにしても、test-case-ruby-backendという名前は悪い。test-case-ruby-test-unit-backendとすべき。