機能テスト冒頭部分の修正、等

2008/12/19

前回は、機能テストのうち main コントローラに関するテストが通るようにしました。

続いて、members コントローラをやっつけましょう。

> ruby test/functional/members_controller_test.rb
(省略)
8 tests, 19 assertions, 1 failures, 2 errors

失敗が 1 個、エラーが 2 個。このくらいなら、すぐ終わりそうです。

エラーの原因は、前回同様ページネーション関係です。

    # 会員一覧
    def index
      (省略)
      
      if params[:group_id]
        @group = Group.find(params[:group_id])
        @members = @group.members.find(:all, options)
        @member_pages = ActionController::Pagination::Paginator.new(
          self, @group.members.size, MEMBERS_PER_PAGE, page)
      else
        @members = Member.find(:all, options)
        @member_pages = ActionController::Pagination::Paginator.new(
          self, Member.count, MEMBERS_PER_PAGE, page)
      end
    end

を、次のように修正します。

    # 会員一覧
    def index
      (省略)
      
      if params[:group_id]
        @group = Group.find(params[:group_id])
        @members = @group.members.all(options).paginate(
          :page => params[:page], :per_page => MEMBERS_PER_PAGE)
      else
        @members = Member.all(options).paginate(
          :page => params[:page], :per_page => MEMBERS_PER_PAGE)
      end
    end

そして、views/members/index.rhtml の次の部分

  <% if @member_pages.page_count > 1 -%>
    <div class="pagination">
    <%= my_pagination_links @member_pages %>
    </div>
  <% end -%>

を次のように修正します。

  <%= will_paginate @members, :previous_label => '前へ', :next_label => '次へ', :inner_window => 2 %>

さて、失敗は test_routing で出ています。

  3) Failure:
test_routing(MembersControllerTest)
    [test/functional/members_controller_test.rb:26:in `test_routing'
     /usr/lib/ruby/gems/1.8/gems/activesupport-2.2.2/lib/active_support/testing/setup_and_teardown.rb:60:in `__send__'
     /usr/lib/ruby/gems/1.8/gems/activesupport-2.2.2/lib/active_support/testing/setup_and_teardown.rb:60:in `run']:
The generated path <"/members/99/edit"> did not match <"/members/99;edit">

『基礎 Ruby on Rails』は Rails 1.2.3 準拠なのですが、Rails 1.2.4 で少し URL の形式が変わりました。

members というリソースを設定して、あるメンバーの情報を編集する入力フォームの URL が /members/99;edit から /members/99/edit に変更されたのです。

ということは、修正すべきはアプリケーション本体ではなくテストの方ということになります。

test/functional/members_controller_test.rb の 26-27 行目を次のように修正してください。

    assert_generates 'members/99/edit',
      { :controller => 'members', :action => 'edit', :id => 99 }

さて、テストを実行すると一応すべて通りますが、警告が表示されます。

> ruby test/functional/members_controller_test.rb
/home/kuroda/hgrepos/books/kiso_rails/cd-rom/chapter9/app/controllers/members_controller.rb:5:
warning: already initialized constant MEMBERS_PER_PAGE
Loaded suite test/functional/members_controller_test
Started
........
Finished in 0.323797 seconds.

8 tests, 37 assertions, 0 failures, 0 errors

この警告は app/controllers/members_controller が二度 require されていることを示しています。

Rails 1.2 時代の機能テストの冒頭は次のように書かれていたのですが、

require File.dirname(__FILE__) + '/../test_helper'
require 'members_controller'

# Re-raise errors caught by the controller.
class MembersController; def rescue_action(e) raise e end; end

Rails 2.2 になると次のようにシンプルになりました。

require 'test_helper'

つまり、コントローラのソースコードを明示的に require する必要はなくなり、コントローラがキャッチするエラーをレイズし直す必要もなくなったのです。

ただし、この Rails 2.2 方式にはちょっと問題があります。

test:functionals タスクを使って全ての機能テストを一括実行する場合はいいのですが、個々のテストスクリプトだけを単体で実行しようとすると

test/functional/members_controller_test.rb:1:in `require': no such file to load -- test_helper (LoadError)
        from test/functional/members_controller_test.rb:1

のように test_helper を require できず、止まってしまうのです。

昔風に次のように書けば大丈夫なのですが、

require File.dirname(__FILE__) + '/../test_helper'

Rails が生成する機能テストをいちいち修正するのは面倒です。

テストスクリプトの実行時に -Itest オプションを付けるのが正しい方法です('-' の次の文字は、大文字の i です)。

> ruby -Itest test/functional/members_controller_test.rb

Ruby インタープリタの -I オプションは、ロードパス(require がファイルをロードする時に検索するディレクトリ)を指定するためのものです。

毎回 -Itest オプションを付けるのが面倒であれば、環境変数 RUBYOPT に '-Itest' をセットしてください。

bash なら

> export RUBYOPT=-Itest

Windows なら

> set RUBYOPT=-Itest

です。

なお、Rails 2.2 でこのような変更が行われた理由については、http://github.com/rails/rails/commit/e8170805 (英語)を参照してください。

これで、members コントローラは OK です。

test:functionals タスクを実行すると…

92 tests, 296 assertions, 3 failures, 6 errors

失敗の数が 4 から 3 に、エラーの数が 8 から 6 に減りました。

本日は、ここまで。