Skip to content.

Sections
Personal tools
You are here: Home » コミュニティ » masarl memorial » homepage3.nifty.com » masarl » article » RubyUnit Tips 集

RubyUnit Tips 集

Document Actions

RubyUnit Tips 集

2001/05/06 作成 石井 勝

はじめに

ここでは Ruby の Testing Framework , RubyUnit で普段僕が使っている Tips を紹介したいと思います.また, RubyUnit を使いやすくするために作っている Emacs Lisp 関数も合わせて解説しましょう.Meadow などで Ruby のプログラムを書いている人はぜひ参考にしてください.

Acceptance Test First

僕の場合, Ruby は開発環境改善のためのツール作成に使っています.ツール作成中は本業のソフトウェア開発を中断させなければならないため,ツール作成に割ける時間といえばせいぜい数時間といったところです.そういう短時間で Ruby のプログラムを書くには,いちいちオブジェクト指向だとかクラス設計だとか悠長なことはいってられません.

そこで,数時間で作成できてしまう規模のプログラムを書くときは, XP でいう Acceptance Test を RubyUnit で最初に書いてしまうのです.どんなクラスを用意し,どんなデザインパターンを使おうか,なーんて高尚なことを考える必要は一切ありません.そんなことは後からコーディング中にリファクタリングすればどうにでもなります.時間が限られている以上,いつツール作成を中止するハメになるかわかりません.今は,とりあえず動くものを作る必要があるのです.そういう状況の下で,短時間にプログラムを作成できるのはこの Acceptance Test First だと思います.

Acceptance Test を RubyUnit でどう書くの? と思う人もいるかもしれません.Ruby の場合,入力された内容にテキスト処理を行い,その結果を標準出力やファイルに表示する場合が多いでしょう.そういうバッチ処理的なプログラムの Acceptance Test を書くには RubyUnit が最適です.ここでは,有名な Hello World プログラムを Acceptance Test するコード例を紹介しましょう.次のようになります:

class HelloTest < RUNIT::TestCase
  def test
    expected =<<XXX
Hello World!
XXX
    actual = `ruby -Ks hello.rb`
    assert_equals(expected, actual)
  end
end

上のテストプログラムでは,バッククォートを使って実際にプログラムを実行し,標準出力が Hello World! になるかどうかを assert_equals メソッドを使って判定しています.この例は単純ですが,Ruby で作るテキスト処理の Acceptance Test はおよそこのパターンになることが多いでしょう.

もちろん,ここでも XP の test a little, code a little, ... のリズムを忘れてはいけません. Acceptance Test を少し書いてはコーディング,その繰り返しで手早くツールを作ってしまいましょう.

注)Win32 環境で cygwin 版 Ruby を使っている人は,DOS ファイルを読みこむと改行コードが \r\n になります.したがって,上のプログラムは cygwin 版 Ruby では

class HelloTest < RUNIT::TestCase
  def test
    expected = "Hello World!\r\n" # <== cygwin 版では \r を付ける
    actual = `ruby -Ks hello.rb`
    assert_equals(expected, actual)
  end
end

と expected にある改行コードすべてに \r をつけなければなりません.あくまで僕の意見ですが,他にも cygwin 版 Ruby はファイルパスが /cygdrive/c/ となったり特殊なので,お薦めしません.特に理由がない限り,Win32 では mingw 版 Ruby をお薦めします.

assert_equals のエラーメッセージを見やすく

RubyUnit が assert_equals を失敗したときに出力するエラーメッセージはデバッグ情報として非常に役立ちます.しかし,assert_equals に渡す文字列が長いものになった場合,どこが間違っているのかすぐに判断することができません.例えば, 次のエラーメッセージ:

assert-equals-test.rb:27:in `test'(AssertEqualsTest): expected:<1. Maple Leaf Rag(1899)
2. Elite Syncopations(1902)
3. Bethena: A Concert Waltz(1905)
4. The Entertainer: A Ragtime Two Step(1902)
> but was:<1. Maple Leaf Rag(1899)
2. Elite Syncopations(1902)
3. Bethena: A Concert Waltz(1904)
4. Combination March(1896)
5. The Entertainer: A Ragtime Two Step(1902)
> (RUNIT::AssertionFailedError)
    from assert-equals-test.rb:42

にある expected と but was の違いがすぐに,しかも正確にわかるでしょうか?

そこで,この2つの値に対してコマンド一発で diff をとれるようにします.幸い Meadow には ediff という非常に便利な機能があるので,それを使ってみると良いでしょう.使ったことがない人が多いかもしれませんので,どんな表示結果になるのか見てください.

ediff 出力結果

一目瞭然ですね.このコマンドを使えるようにするための Emacs Lisp 関数が書かれたファイルを用意しておきました.自由に使ってください(ちなみに,僕が Emacs Lisp でプログラムを書くときは Test First してません(泣)).

使い方は,*compilation* バッファに表示された RubyUnit の出力に対して M-x ediff-runit-expected-but-was と実行するだけです.コマンド名が長いので,必要に応じてキーバインドをしておくとよいでしょう.ここで,表示されたあとの ediff の使い方を簡単に説明します. n で 次の相違点,p で前の相違点にジャンプします. q を押すと ediff が終了します.