2014年12月にRuby 2.2がリリースされる予定です*1。
Ruby 2.2にはRuby 1.9.1のときに外されたtest-unitというテスティングフレームワークが再びバンドルされる予定です。Rubyのテスティングフレームワーク周りに詳しくない人にはよくわからない状況でしょう。そこで、Rubyのテスティングフレームワークの歴史を説明することで状況を整理します。
この説明の中ではたくさんのテスティングフレームワークが登場します。似たようなものもあるため、最初にテスティングフレームワークの名称を整理します。この説明の中で登場する名称は次の通りです。
違いがわかりますか?ざっくり説明すると次の通りです。
それでは、歴史を振り返りながらRubyのテスティングフレームワークを整理しましょう。
Ruby 1.6の頃はRubyはテスティングフレームワークをバンドルしていませんでした。
テスティングフレームワークが広まるきっかけになったのはエクストリーム・プログラミング(XP)です。最初のXPの本が出版されたのが1999年です。日本語版は2000年の12月です。この本の影響*2でSmalltalkやJava以外でのテスティングフレームワークの実装がでてきました。もちろん、Ruby用の実装もでてきました。
Lapidaryのサイトを見ると、最初のバージョンがリリースされたのが2011年3月です。ちなみに、Lapidaryの作者は後述するTest::Unitの作者で、海外の人です。
同じく、RubyUnitのサイトを見ると、最初に公開された*3のが2011年9月です。ちなみに、RubyUnitの作者はRubyにバンドルされているWin32OLEの作者で、日本の人です。
当時、walkitというテスティングフレームワークもあったようですが、インターネット上から情報を見つけることはできませんでした。
Ruby用のテスティングフレームワークがでてくると、Ruby本体にバンドルしようという話が進みます。
日本Rubyの会の高橋代表理事の2001年10月の日記によると、Lapidaryの作者がLapidaryとRubyUnitを統合したTest::Unitを作って、それをRuby本体にバンドルすることになったそうです。ただし、Ruby 1.6の間はRuby本体にバンドルされませんでした。
ここまでのまとめです。
2003年8月にリリースされたRuby 1.8.0にTest::Unitがバンドルされました。なお、既存のRubyUnitユーザーのことも配慮して、Test::UnitはRubyUnit互換のAPIを提供していました。これがrubyunitです。ちなみに、rubyunitという表記はるりま以外では見たことはありません。
Ruby 1.8にはTest::Unitがバンドルされていました。requireするときはrequire "test/unit"と書くことからtest/unitとも呼ばれるようになりました。
ポイント:Ruby 1.8の頃にtest/unitと言ったらTest::Unitのこと。
さて、Ruby 1.8にバンドルされたTest::Unitですが、2003年の間はそこそこ活発に開発が続いていました。しかし、それ以降はほとんど改良はありませんでした。この状況はRuby 1.9.1がリリースされる2007年12月まで変わりませんでした。
そんなTest::Unitがのんびり暮らしていた2005年にRSpecの最初のバージョンがリリースされました。RSpecの開発は活発で便利な機能が追加されていきます。RSpecの記法がよいと思う人と記法に抵抗がない人は、便利なのでTest::UnitではなくRSpecを使うようになっていきました。
Test::Unitの開発が停滞していることに不満を感じている人が2人いました。後のminitestの作者と、後のtest-unitの開発者です。
minitestの作者はTest::Unitのメンテナーになりました。メンテナーになったminitestの作者は、Test::Unitは複雑すぎて自分はメンテナンスできないと主張しました。
ここまでのまとめです。
2007年12月にリリースされたRuby 1.9.0で、Test::Unitが提供しているRubyUnit互換APIは削除されました。
2009年1月にリリースされたRuby 1.9.1ではTest::Unit自体もRuby本体から外れました。何があったのでしょうか。
後のminitestの作者は複雑すぎてTest::Unitをメンテナンスできないため、もっと小さなテスティングフレームワークにしなければいけないと考えました。その考えのもと作ったのがminiunitです。miniunitはRuby 1.9.0に入りそうになりましたが、後のtest-unitの開発者が反対したためRuby 1.9.0には入らずRuby 1.9.1でRuby本体に入りました。この間にminiunitからminitestに名前が変わっています。
minitestがRuby本体にバンドルされたタイミングでTest::UnitはRuby本体から外れました。Ruby本体から外れたTest::Unitはtest-unitというgemになります。test-unitというgemはこれをベースに今でも改良を続けています。
Test::UnitはRuby本体から外れましたが、Test::Unit互換APIは残りました。なぜならRuby本体のテストはTest::UnitのAPIで書かれていたからです。テスティングフレームワークが変わったからといって既存のテストを書き直さないといけないのは受け入れられなかったのです。
このminitestの上に実装されたTest::Unit互換APIをtest/unitと呼んでいます。
ポイント:Ruby 1.9の頃にtest/unitと言ったらminitestの上に実装されたTest::Unit互換APIのこと。Test::Unitのことではない。
ここまでのまとめです。
2013年2月にRuby 2.0.0がリリースされました。テスティングフレームワークについて特筆すべきことはありません。minitestもtest-unitもRSpecもどれも停滞することなく開発が続いています。
2013年12月にRuby 2.1.0がリリースされました。2014年11月現在の最新の安定版です。
test/unit(minitestの上に実装したTest::Unit互換API)に陰りが見えてきました。minitestがminitest 5.0.0で後方互換性のないAPIの変更を導入したのです。
この非互換の変更をうけてtest/unitはメンテナンスできなくなりました。Ruby開発チームとしては既存のテストを動かすためにtest/unitは必要です。しかし、最新のminitestでは動きません。つまり、Ruby本体に最新版のminitestをバンドルできなくなったということです。
この状況に対応するため、Ruby本体のテストはminitest 4とその上に実装されたtest/unitで動かすことにしました。ただし、このminitest 4とtest/unitはRubyユーザー向けのものではなく、Ruby開発チームだけが使うものとしました。minitestとtest/unitはRubyのソースの中ではlib/minitest/とlib/test/unit*に置かれていましたが、それをtest/lib/以下に移動しました。
移動前:
lib/minitest/*.rb lib/test/unit.rb lib/test/unit/**/*.rb
移動後:
test/lib/minitest/*.rb test/lib/test/unit.rb test/lib/test/unit/**/*.rb
これで、最新版のminitestをバンドルしてもRuby本体のテストはそのまま動き続けるようになりました。
ポイント:Ruby開発チームの中でtest/unitというとtest/lib/以下にあるtest/unitのことを指す。
ここまでのまとめです。
Ruby本体のテスト用のminitestとtest/unitをtest/lib/以下に動かすことにより最新のminitestをバンドルできるようになりました。
しかし、このままRuby 2.2.0をリリースするとTest::Unit互換APIがなくなってしまいます。さらに、minitestはAPIの互換性がなくなっているので既存のテストはそのままでは動きません。つまり、既存のRubyが提供しているminitestまたはtest/unitを使っているユーザーはRuby 2.2.0にアップグレードするとテストが動かなくなるということです。
それだとあんまりだということで、Test::Unit互換APIを提供するためにRuby 2.2.0にはminitestだけでなくtest-unit(gemとなって開発が続いていたTest::Unit)がバンドルされることになりました。
なお、Ruby開発チーム的にはRSpecをバンドルするという選択肢はありませんでした。
ポイント:Rubyユーザーがtest/unitというとtest-unitのことを指すことになるかもしれない。
ここまでのまとめです。
Ruby 2.2.0にどうしてtest-unitが再バンドルされるのかを、Rubyのテスティングフレームワークの歴史をたどりながら説明しました。10年以上前のサイトが今でもアクセスできると昔のことを確認するときにとても便利ですね。
Ruby 1.9.1でTest::UnitがRuby本体から外れた後、Test::Unitはtest-unit gemとして開発が続いてきました。Ruby 2.2.0で再バンドルされるのを機にtest-unitも触ってみてはいかがでしょうか?Test::Unitの頃しか知らない人はかなり便利になっていることに驚くでしょう。
最近のtest-unit関連情報: