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 (※英文)
追記ここまで ===
Ruby や Ruby 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
- https://rubygems.org/gems/minitest
この Minitest よりも機能が増えている、「test-unit」というものもある。
- Test::Unit (test-unit)
- https://rubygems.org/gems/test-unit
この test-unit に関しては、repeatedly さんの下記の記事が詳しい。
追記ここまで ===
Ruby 環境は以下の通り。
Ruby | ruby 1.9.3p448 |
Ruby on Rails | 3.2.13 |
以下に、Minitest(Test::Unit)を Ruby on Rails で使うための簡単な解説を掲載する。
参考記事
- A Guide to Testing Rails Applications ― Ruby on Rails Guides
- Test::Unit に関して Unit, Functional, Integration テストの必要十分な解説がある。
使い方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」テストのみ紹介する。
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