Test::Unit 2.0.1が RubyForge上でリリースされました。RubyGemsも提供されているの で以下のようにインストールできます。
% sudo gem install test-unit
Test::UnitはRuby 1.8.xに標準添付されている単体テストフレーム ワークです。しかし、Ruby 1.9.1からは miniunitが標準 添付され、Test::UnitはRubyForgeで開発が継続されることになりま した。これからもTest::Unitを使うときはRubyGemsでインストール することになるでしょう。
Ruby 1.8.xに標準添付されているTest::Unitは互換性のために、 Test::Unit 1.2.3としてリリースされています。Ruby 1.9.1でも Ruby 1.8.xに標準添付されているTest::Unitと同じTest::Unitを使 用したい場合は以下のようにします。
% sudo gem install test-unit --version '= 1.2.3'
テストファイル内(変更前):
1 2 |
require 'test/unit'
...
|
テストファイル内(変更後):
1 2 3 4 |
require 'rubygems' gem 'test-unit', '= 1.2.3' require 'test/unit' ... |
余談ですが、Ruby 1.9.1でTest::Unitが標準添付から外れ、 miniunitが標準添付になったのはTest::Unitのソースがメンテナン スしづらくなっていたのが主な理由です。
Ruby 1.8.xに標準添付されているTest::Unitは長い間メンテナンス はされていましたが、特に機能拡張などは行われていませんでした。 しかし、その間にもテスト環境を便利にするライブラリが公開され てきました。例えば、RSpecのような BDD用のフレームワークや、 expectations のような軽量の単体テストフレームワーク、 Shoulda/ test/spec/ Mochaのように Test::Unitを拡張するライブラリなどです。Test::Unitは少し時代 遅れになってしまったのです。
最近のテスト用のフレームワークは DSL化の方向に向かっているようにも見えます。 これはRSpecの影響が大きいのでしょう。expectationsやShouldaもテスト用の DSLを提供します。
しかし、Test::UnitはDSLを提供しません。テストを「英語らしく」 ではなく「Rubyプログラムらしく」書きます。好みにもよりますが、 これはTest::Unitのメリットの1つと言えます。
Test::Unitに他のフレームワークやライブラリの機能を、 Test::Unitの「Rubyプログラムらしく」テストを書ける特性を活か したまま追加すれば、Test::Unitはもっと便利で使いやすいテスト フレームワークになるでしょう。Test::Unit 2.x系列はRuby 1.8.x に標準添付されていた頃とは違い、そのような方針の元で活発に開 発されていく系列になります。
例えば、以下のような機能が他のフレームワークやライブラリから 移植されています。
ここでは「差分表示」と「ネストしたテスト定義」だけ紹介します。 *1
RSpecでは比較結果が異なった場合に差分を表示して違いをわかり やすく表示してくれます。
diff_spec.rb:
1 2 3 4 5 6 7 8 |
require 'rubygems' require 'spec' describe String do it do ["I", "am", "a", "boy"].join("\n").should == ["I", "was", "a", "boy"].join("\n") end end |
実行結果(差分表示部分のみ):
% ruby diff_spec.rb -D ... Diff: @@ -1,5 +1,5 @@ I -was +am a boy ...
同様の機能がTest::Unit 2.0.1にもあります。
test_diff.rb:
1 2 3 4 5 6 7 8 9 10 |
require 'rubygems' gem 'test-unit' require 'test/unit' class TestDiff < Test::Unit::TestCase def test_diff assert_equal(["I", "am", "a", "boy"].join("\n"), ["I", "was", "a", "boy"].join("\n")) end end |
実行結果(差分表示部分のみ):
% ruby test_diff.rb ... diff: I - am + was a boy ...
この例では、ほとんど同じ差分表示ですが、Test::Unit 2.0.1の 差分表示がRSpecの差分表示よりも便利なこともあります。
今度は"\n"ではなく" "でjoinして1行の文字列として比較します。
test_diff.rb:
1 2 3 4 5 6 7 8 9 10 |
require 'rubygems' gem 'test-unit' require 'test/unit' class TestDiff < Test::Unit::TestCase def test_diff assert_equal(["I", "am", "a", "boy"].join(" "), ["I", "was", "a", "boy"].join(" ")) end end |
実行結果(差分表示部分のみ):
% ruby test_diff.rb ... diff: - I am a boy ? ^ + I was a boy ? + ^ ...
Test::Unit 2.0.1では必要なら同じ行のうち、どの列が異なってい るのかも表示します。RSpecでは行単位の差分までで列単位までの 差分は表示しません。
余談ですが、この差分表示形式はPython の difflib ライブラリで使われている形式です。
Shouldaではcontextをネストさせることにより、便利にテストを書 くことができます。以下はShouldaのページからの引用です。 *2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class UserTest < Test::Unit::TestCase context "A User instance" do setup do @user = User.find(:first) end should "return its full name" do assert_equal 'John Doe', @user.full_name end context "with a profile" do setup do @user.profile = Profile.find(:first) end should "return true when sent #has_profile?" do assert @user.has_profile? end end end end |
ネストされた"with a profile"のcontext内では上位の"A User instance"のcontext内のsetupが実行された後に実行されます。つ まり、以下のような実行順序になります。
実行されるフィクスチャ(setup)がネストで自然に表現されていま す。
Test::Unit 2.0.1では以下のように書きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class UserTest < Test::Unit::TestCase def setup @user = User.find(:first) end def test_full_name assert_equal('John Doe', @user.full_name) end class ProfileTest < UserTest def setup super @user.profile = Profile.find(:first) end def test_profile assert_true(@user.has_profile?) end end end |
これは以下のように実行されます。
実行されるフィクスチャ(setup)がネストとクラス階層で自然に表現 されています。
Test::UnitはRuby 1.9.1からは標準添付ではなくなりましたが、 Test::Unit 2.xとして活発に開発が続けられています。既存の他の フレームワークやライブラリのよいところは積極的に導入している ため、Ruby 1.8.xに標準添付されているTest::Unitよりもはるかに 使いやすくなっています。
今回は紹介しませんでしたが、他のフレームワークやライブラリに はないTest::Unit 2.x独自の便利な機能もあります。Test::Unitの 「Rubyプログラムらしい」テストの書き方が好きな場合はこれから もTest::Unitを使ってみてはいかがでしょうか。