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'
テストファイル内(変更前):
require 'test/unit'
...
テストファイル内(変更後):
require 'rubygems'
gem 'test-unit', '= 1.2.3'
require 'test/unit'
...
余談ですが、Ruby 1.9.1でTest::Unitが標準添付から外れ、 miniunitが標準添付になったのはTest::Unitのソースがメンテナン スしづらくなっていたのが主な理由です。
Test::Unit 2.x
Ruby 1.8.xに標準添付されているTest::Unitは長い間メンテナンス はされていましたが、特に機能拡張などは行われていませんでした。 しかし、その間にもテスト環境を便利にするライブラリが公開され てきました。例えば、RSpecのような ビヘイビア駆動開発用のフレームワークや、 expectations のような軽量の単体テストフレームワーク、 Shoulda/ test/spec/ Mochaのように Test::Unitを拡張するライブラリなどです。Test::Unitは少し時代 遅れになってしまったのです。
最近のテスト用のフレームワークは ドメイン固有言語化の方向に向かっているようにも見えます。 これは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 に標準添付されていた頃とは違い、そのような方針の元で活発に開 発されていく系列になります。
例えば、以下のような機能が他のフレームワークやライブラリから 移植されています。
- 差分表示
- ネストしたテスト定義
- 色付け
- C-cでテスト中断時にもテスト結果を表示
- 複数のsetup/teardown
- ...
ここでは「差分表示」と「ネストしたテスト定義」だけ紹介します。 1
差分表示
RSpecでは比較結果が異なった場合に差分を表示して違いをわかり やすく表示してくれます。
diff_spec.rb:
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:
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:
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
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: "A User instance" context
- should: "return its full name"
- setup: "A User instance" context
- setup: "with a profile" context
- should: "return true when sent #has_profile?"
- setup: "with a profile" context
実行されるフィクスチャ(setup)がネストで自然に表現されていま す。
Test::Unit 2.0.1では以下のように書きます。
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
これは以下のように実行されます。
- UserTest#setup
- UserTest#test_full_name
- UserTest#setup
- UserTest::ProfileTest#setup
- UserTest::ProfileTest#test_profile
- UserTest::ProfileTest#setup
実行されるフィクスチャ(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を使ってみてはいかがでしょうか。