機能試験
controller な試験を書いてみる事に。
参考にしたのは http://jp.rubyist.net/magazine/?0013-RubyOnRails#l15
とりあえず、controller を作成しないとナニ。
$ ./script/generate controller task exists app/controllers/ exists app/helpers/ create app/views/task exists test/functional/ create app/controllers/task_controller.rb create test/functional/task_controller_test.rb create app/helpers/task_helper.rb $ ./script/generate controller ajax exists app/controllers/ exists app/helpers/ create app/views/ajax exists test/functional/ create app/controllers/ajax_controller.rb create test/functional/ajax_controller_test.rb create app/helpers/ajax_helper.rb $
試験を書くのですが、機能試験的には
- ブラウザから渡されるパラメータ
- サーバが返却するレスポンスやデータ
の確認を実施との事。
確認可能なレスポンスのナニは
- HTTP レスポンス
- レンダリングしたテンプレートの名前
- view に渡された変数の値
- session、flash
- テンプレートを元に出力された HTML タグの値
等が確認可能との事。
とりあえず、簡単なのから検討してみると task コントローラの index アクションは List を全件ナニして @lists に渡している。render するのは task/index ?
気になるのは index.rhtml から何段かに渡って render してるんですが、これはどうなるんだろうか。コードとしては以下のような感じッスか?? (とりあえず、インスタンス変数のチェキは別途)
def test_index get :index assert_response :success assert_template 'index' end
動かしてみたが、当然の如く index というアクションが無い、との返答。task_controller.rb を実装してみます。
と、
- find_all に文句を言われる
- default.rhtml が無い、と文句を言われる
げ。当たり前だな。default.rhtml はコピっておこう。で実行すると今度は index.rhtml がねぇと。で、再度実行すると、render してる _list.rhtml も要求されているらしい。touch で空なナニを作成するとどうなるかな。
$ touch app/views/task/_list.rhtml $ touch app/views/task/_item.rhtml $ ls app/views/task _item.rhtml _list.rhtml index.rhtml $ ls app/views/layout default.rhtml $ ruby test/functional/task_controller_test.rb Loaded suite test/functional/task_controller_test Started .. Finished in 0.085107 seconds. 2 tests, 3 assertions, 0 failures, 0 errors $
を、通った。ファイルがあれば良いのか??とゆー事で default.rhtml と index.rhtml を両方空にして再度実行してみる。
$ rm app/views/layout/default.rhtml $ rm app/views/task/index.rhtml $ touch app/views/layout/default.rhtml $ touch app/views/task/index.rhtml $ ruby test/functional/task_controller_test.rb Loaded suite test/functional/task_controller_test Started .. Finished in 0.039895 seconds. 2 tests, 3 assertions, 0 failures, 0 errors $
げ、通った。てか、layout/default.rhtml と task/index.rhtml だけで良さげ。
$ rm app/views/task/_*.rhtml $ ruby test/functional/task_controller_test.rb Loaded suite test/functional/task_controller_test Started .. Finished in 0.040804 seconds. 2 tests, 3 assertions, 0 failures, 0 errors $
つーか、index アクションは index しかレンダーしてないとゆー認識で良いのかなぁ。その先って試験の要素としては見てなさげではある。できあがり状態で試してみる必要はあるかも。
とりあえず、view なナニのサイズが 0 で良いとゆー事は製造の順番としては model → controller → view ってコトになるのかなぁ。しかも view は目視? ただ、test ディレクトリの mocks だの integration だのとゆーディレクトリも気になる。
で、変数見るために assert を追加
def test_index get :index assert_response :success assert_template 'index' assert_equal lists(:first).id, assigns(:lists)[0].id assert_equal lists(:another).id, assigns(:lists)[1].id end
とりあえず試験としては通ってるんですが、lists のコレクションを map して assigns(:list) の map なナニと assert_equal ってワザは使えんのかなぁ。(lists のコレクションって言い方微妙スギ)
この調子で ajax なコントローラの試験も検討してみる。以下にアクション列挙。メソドは基本的に POST のはず。
- add_list
- パラメータとして :title が渡される
- save に成功したら task/list がテンプレートでステータスは 200
- テンプレートに渡されるのは list
- save に失敗したらどうなるんだろ (テンプレートは同じ??)。ステータスは 406
- destroy_list
- パラメータとして :id が渡される
- :id なナニは destroy される
- 存在しない :id だと??
- テンプレートはなし
- add_item
- パラメータとして :id と :note が渡される
- save は共通なんで成功なパターンのみ試験で良いはず
- completion_item
- パラメータとして :id が渡される
- completion 列が toggle! される
- テンプレートなし (:nothing??)
- edit_item
- パラメータとして :id と :value が渡される
- :value が空の場合、Item.fine(:id) な行が destroy される
- :value が空でない場合、note 列が更新
- テンプレートは指定なし。(item??)
- update_positions
- パラメータとして :sortable_list が渡される。これは id の配列。
- 渡された id の配列順に position が更新
- テンプレートなし
とりあえず、上記を元に試験を add_list を書いてみて実行してみる。
def test_add_list post :add_list, :title => 'adding' assert_template 'task/_list' assert_response :success end
テンプレートの名前はファイル名じゃないと駄目らしい。一応試験は通ったぽい。
$ ruby test/functional/ajax_controller_test.rb Loaded suite test/functional/ajax_controller_test Started .. Finished in 0.069392 seconds. 2 tests, 3 assertions, 0 failures, 0 errors $
レコード追加の確認したいんですが、どうすりゃええんでしょうか。こんな感じ??
assert_equal 'adding', List.find(3).title
ええと、違うな。レコード追加は model の仕事だからこっちじゃ確認しなくて良い? ま、いいや。とりあえずそゆ事にしておいて、request/responce のナニだけを確認しましょう。
でも、render_add とか render_destroy の試験はデキるか。て、protected なんで無理? これもスルーしておこう。なんかダメダメだなぁ。
で、一応全部の試験を実装してみたんですが、render も :text とかって assert_template で確認できないみたい。(本当か??)
追記
test_add_list ん中で、 p List.find(:all) してみたら追加されたレコードの id が 32 とかになっているのを発見。仕方がないので以下のような assert を追加。
assert_equal 3, List.find(:all).entries.length
追記 2
test ディレクトリの中に integration というナニがある。ググッてみた所、rails 1.1 で新たに導入されたものらしい。
追記 3
とりあえず、書いた試験を以下に。
test/functional/ajax_controller_test.rb
require File.dirname(__FILE__) + '/../test_helper' require 'ajax_controller' # Re-raise errors caught by the controller. class AjaxController; def rescue_action(e) raise e end; end class AjaxControllerTest < Test::Unit::TestCase fixtures :lists, :items def setup @controller = AjaxController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new end # Replace this with your real tests. def test_truth assert true end def test_add_list post :add_list, :title => 'adding' assert_template 'task/_list' assert_response :success assert_equal 3, List.find(:all).entries.length end def test_destroy_list post :destroy_list, :id => 1 assert_response :success assert_raise(ActiveRecord::RecordNotFound) {List.find(1)} end def test_add_item post :add_item, :id => 1, :note => 'zzzzzz' assert_response :success assert_template 'task/_item' assert_equal 'zzzzzz', List.find(1).items.last.note end def test_completion_item assert_equal items(:first).completion, Item.find(1).completion post :completion_item, :id => 1 assert_equal items(:first).completion, !Item.find(1).completion end def test_edit_item post :edit_item, :id => 1, :value => 'xxxxx' assert_equal 'xxxxx', Item.find(1).note post :edit_item, :id => 1, :value => "" assert_raise(ActiveRecord::RecordNotFound) {Item.find(1)} end def test_update_positions post :update_positions, :sortable_list => [3, 2, 1] assert_equal 0, Item.find(3).position assert_equal 1, Item.find(2).position assert_equal 2, Item.find(1).position end end