give IT a try

プログラミング、リモートワーク、田舎暮らし、音楽、etc.

RSpecの開発者が語る、RSpecとMinitestの利点

はじめに

先日、MinitestとRSpecを比較するこんな記事を書きました。

blog.jnito.com

MinitestとRSpecの比較記事はネットにたくさんありますが、その中の一つにRSpecのメイン開発者であるMyron Marston氏によって書かれた記事(回答)がStackoverflowに載っています。

ruby on rails - Minitest and Rspec - Stack Overflow
f:id:JunichiIto:20150511063650p:plain

2012年9月の回答なので現在では状況が変わっている点も多少あるかもしれませんが、なかなか興味深い内容だったので翻訳してみました。

質問:MinitestとRSpecについて

ついさっきMinitestを解説しているRailscastを視聴しました。

Railsアプリケーションをテストする場合、RSpecとMinitestではどのような長所と短所がありますか?
RSpecをMinitestに書き換える場合、Minitestではどんな機能が使えなくなりますか?

Myron Marston氏の回答

私はRSpecの開発者の一人です。
Minitestは使ったことがありません。
なので私の回答には多少バイアスが入っていることを予めご了承ください。


RSpec全体に言える話として、RSpecの豊富な機能はテストの概念を第一級オブジェクト(first class objects)として具現化している点に由来しています。
Test::UnitやMinitestはアサーションを実行するために単純なメソッドを使うのに対し、RSpecでは第一級オブジェクトのマッチャ(matcher)を使います。
第一級オブジェクトなので否定形のテストで使ったり、テストの結果を自己記述したりすることができます。


RSpecのexampleも第一級オブジェクトで、豊富なメタデータを扱えます。


Spec形式のMinitest(minitest/spec)では it ブロックを単純なメソッドに変換します。
なのでRSpecのように豊富なメタデータをサポートしません。


RSpecでは第一級の構造を使って振る舞いを共通化することができます(shared exampleのことです)。
これも引数を取ることができます。


一方、Minitestでは継承やMixinを使ってテストを再利用することができます。
しかし、第一級オブジェクトと同じ事はできません。


RSpecではフォーマッタAPIが明確に定義されています(数多く存在するサードパーティ製のフォーマッタはそれを使っています)。
Minitestが同じように第一級オブジェクトとしてフォーマッタAPIを定義しているかどうか私は知りません。


毎日のようにテストを実行し、TDDを実践している開発者の一人として、私は上記のようなRSpecの機能がとても便利だと感じています。
とはいえ、そこまでの機能はいらない、学習コストが高すぎる、というように考える人も多いようです。


Minitestでは実装されていないと思われるRSpecの便利な機能を具体的に挙げてみましょう。

  • before(:all) フック(ただし、これはパワーユーザー向けの機能で頻繁に使われるものではありません。私もこれまでに数回使っただけです)
  • around(:each) フック
  • Shared examples
  • Shared contexts
  • RSpecの動きを制御するための豊富なメタデータ。メタデータを使うと、どのexampleを実行するのか、どのexampleグループをshared contextsに含めるのか、どのexampleグループをモジュールに含めるのか、といったことを制御できます。
  • rspec-mocksとして最初からサポートされているモック関連の豊富な機能。RSpecのモックに比べるとMinitest::Mockはシンプルすぎて機能があまり豊富ではありません。
  • rspec-fireという素晴らしい機能。(訳注:rspec-fireの機能はRSpec 3から標準実装されているようです)

 

Minitestの利点も挙げてみます。

  • Rubyの標準ライブラリとして組みこまれているので、追加インストールが不要。
  • "def test_xxx" とも "it 'xxx'" とも書くことができる。
  • 本体のソースコードがとても小さくてシンプル。それに比べるとRSpecは歴史が長くて機能も多いため、ソースコードが大きい。
  • RSpecよりもロード時間が短い(Minitestが読み込むのは約4ファイル。一方RSpecは3つのgemにまたがる多数のファイルを読み込む)。とはいえ、RSpecが常に遅いというわけではありません。私が関わっているプロジェクトではほとんど1秒以下でテスト結果が返ってきます(500ms以下であることが多いです)。

 

結局のところ、MinitestとRSpecの関係はSinatraとRailsの関係に似ているところがあります。
ニーズに応じて使えばどちらも良い選択肢になるはずです。


最後に一言。
MinitestとRSpecのそれぞれで気に入っている点がある場合、互いに組み合わせて使うこともできます。
こちらのブログエントリをご覧ください。

まとめ(僕の感想)

「ニーズに応じて使えばどちらも良い選択肢になる」というのは僕もその通りだと思います。
どちらか一方が万能で常に優れている、というわけではないですよね。
みなさんもそれぞれの長所、短所を考慮しながら適切なテスティングフレームワークを選んでみてください。

2015.06.30 追記「RSpecユーザのためのMinitestチュートリアル」という本を書きました

電子書籍「Everyday Rails - RSpecによるRailsテスト入門」の追加コンテンツとして「RSpecユーザのためのMinitestチュートリアル」を公開しました。
詳しくは以下のエントリをご覧ください。

blog.jnito.com