Ruby on Rails 3.2.x: Minitest(Unit::Test)を使った、ユニットテスト、ファンクショナルテスト事始め

追記 2014-12-10 ===

この記事ですが、Ruby on Rails 3.2.x 系を前提にした内容となっており、
新しい Rails 4.0.x、4.1.x 系では少しやり方が異なります。

取り急ぎで申し訳ございませんが、とりあえず下記に、最新の Minitest の記事を紹介いたします。
A Guide to Testing Rails Applications — Ruby on Rails Guides (※英文)

追記ここまで ===




RubyRuby on Rails で使用されるテストフレームワークは、何がポピュラーか?

RSpec が第1党で、次に Minitest という Test::Unit から置き換えられたフレームワークが人気だ。個人的には RSpec を使う機会が多かったが、私としては Minitest(Test::Unit)を使っていこうかなと考えている。RSpec は利用者が多いため情報・実例は豊富だが、個人的に思想が好きではない。Minitest(Test::Unit)だって古くからずっと使われているし、Rails も Minitest(Test::Unit)でテストされているので、選択肢としては悪くないはずだ。

私は、下記の意見に非常に共感する。


追記 2014-11-25 ===

この記事では、Ruby に標準で入っている Minitest について紹介している。

この Minitest よりも機能が増えている、「test-unit」というものもある。

この test-unit に関しては、repeatedly さんの下記の記事が詳しい。

追記ここまで ===

Ruby 環境は以下の通り。

Ruby ruby 1.9.3p448
Ruby on Rails 3.2.13

以下に、Minitest(Test::Unit)を Ruby on Rails で使うための簡単な解説を掲載する。



参考記事

使い方1(Test::Unit はどのようにロードされているのか?)

Rails の 3.2.x 系では、Test::Unit は標準でビルトインされる。「./config/application.rb」には下記のような記述があると思う。

require File.expand_path('../boot', __FILE__)

require 'rails/all'

if defined?(Bundler)
  # If you precompile assets before deploying to production, use this line
  Bundler.require *Rails.groups(:assets => %w(development test))
  # If you want your assets lazily compiled in production, use this line
  # Bundler.require(:default, :assets, Rails.env)
end
...

「require 'rails/all'」によって、次のコードが実行されている。

require "rails"
 
%w(
    active_record
    action_controller
    action_mailer
    rails/test_unit
    sprockets
).each do |framework|
  begin
    require "#{framework}/railtie"
  rescue LoadError
  end
end

rails/test_unit」という記述が!


使い方2(Rails 上の Test::Unit ディレクトリ構成)

Rails アプリケーションを作成すると、下記のようなテスト用ディレクトリ・ファイルが用意される。

  • test_helper.rb
  • unit
  • performance
    • browsing_test.rb
  • integration
  • functional
  • fixtures
test_helper.rb
ENV["RAILS_ENV"] = "test"
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'

class ActiveSupport::TestCase
  # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
  #
  # Note: You'll currently still have to declare fixtures explicitly in integration tests
  # -- they do not yet inherit this setting
  fixtures :all

  # Add more helper methods to be used by all tests here...
end

見ての通り、RAILS_ENV に test を設定し、environment(環境情報)のロードを行なっている。



unit

このディレクトリの説明をする前に、テストの種類に関して簡単に説明しなければならない。
ざっくばらんに言うと、Rails では主に次の3つのテストに対応している。

Unit テスト モデル単体のテスト、ライブラリ単体のテスト
Functional テスト コントローラーのテスト
Integration テスト 実際にユーザーが操作した時のような、複数のコントローラーにまたがる総合テスト

今回は、私の独断と偏見により「Unit」と「Functional」テストのみ紹介する。

この unit ディレクトリは、文字通り Unit テストを記述するためのディレクトリである。



performance

パフォーマンステスト用らしいが、今回は割愛。



integration

Integration テスト用らしいが、今回は割愛。



functional

Functional テストを記述するためのディレクトリ。



fixtures

Fixtures(フィクスチャー)とは、テストを実行する上で、予め DB に投入しておく検証用データのこと。Fixtures が多くなりすぎると、管理も非常に大変になる&どのようなデータが投入されているか、頭に入れて置かなければいけなくなる。Fixtures の内容は、非常に内容を絞るか、厳選したほうが良いのではないかな?と勝手に予想している。
とりあえず私は、最初のうちはできるだけ Fixtures に頼らないように進めてみようと思っている。

使い方3(とりあえず Test を実行してみる)

テストを実行するための下準備として、次のコマンドを実行する。

$ bundle exec rake db:migrate
$ bundle exec rake db:test:load

「db:test:load」は database.yml の test 環境に記述されている database に対し、テスト用の DBとスキーマを作成する。この時参照されるのは「schema.rb」なので、「db:migrate」によって「schema.rb」を最新の状態にしておくとトラブルを防げる。


テストの実行は非常に簡単。次のコマンドで全てのテストを実行できる。

$ bundle exec rake test

Unit テストのみ実行する場合は、次の通り。

$ bundle exec rake test:units

Functional テストのみ実行する場合は、次の通り。

$ bundle exec rake test:functionals

特定のテストファイルのテストのみを実行する場合は、次の通り。

$ bundle exec rake test:units TEST="test/unit/example_test.rb"
$ bundle exec rake test:functionals TEST="test/functional/example_controller_test.rb"

使い方4(とりあえず簡単な Test を書いて、実行してみる)

Article というモデルがあるとして、これが正しく save 出来るかの Unit テストを記述してみる。

# ./test/unit/article_test.rb
# -*- encoding: utf-8 -*-

require "test_helper"

class ArticleTest < ActiveSupport::TestCase

  test "Article オブジェクトの正常系 save を検証する" do
    article = Article.new({
      :title => "test title",
      :body => "test body"})
    
    assert(article.save, "Article オブジェクトの DB save に失敗した")
  end
end


次に、Article コントローラの Functional テストを記述してみる。

# ./test/functional/articles_controller_test.rb
# -*- encoding: utf-8 -*-

require "test_helper"

class ArticlesControllerTest < ActiveSupport::TestCase
  test "GET root" do
    get :index    
    assert_response(:success, "レスポンスステータスが異常である")
  end
end


テストを実行する。

$ bundle exec rake test
> Run options:
> 
> # Running tests:
> 
> .
> 
> Finished tests in 0.104013s, 9.6142 tests/s, 19.2284 assertions/s.
> 
> 1 tests, 1 assertions, 0 failures, 0 errors, 0 skips
> Run options:
> 
> # Running tests:
> 
> .
> 
> Finished tests in 0.039497s, 25.3184 tests/s, 25.3184 assertions/s.
> 
> 1 tests, 1 assertions, 0 failures, 0 errors, 0 skips

使い方5(いろいろな Assersion)

Test::Unit の assert にはいくつか種類があるので、ここで参考URLを紹介する。

Rails Guide にも結構のってた。

導入は以上