ActiveSupport_TestCase + shoulda によるテスト の履歴(No.1)
更新- 履歴一覧
- 差分 を表示
- 現在との差分 を表示
- ソース を表示
- ソフトウェア/rails/ActiveSupport_TestCase + shoulda によるテスト へ行く。
ActionController::TestCase + shoulda による Ruby on Rails コントローラのテスト†
- ActionController::TestCase は Rails 標準のコントローラテストフレームワーク
- shoulda は読みやすいテストケースを書くための gem
これらを使ってコントローラをテストするためのノウハウをメモとして残したい
いろいろ検討中†
まだちゃんとしたテストは書き始めたばかりなので全然やり方が定まってません。 このレベルの物をこんなところに晒すのも何なのですが、とりあえずメモとして書いちゃいます。
#coding: utf-8
require 'test_helper'
class AccountControllerTest < ActionController::TestCase
tests AccountController # この例のように標準的な命名をしている限り、
# コントローラ名の指定はしなくてもOK
# すべての context に共通の初期化処理
setup {
clear_all
# ActionController::TestCase にて、以下のクラス変数が使われている。
#
# @@required_fixture_classes: false
# @@already_loaded_fixtures: {}
# @@test_suites: {ActiveSupport::TestCase=>true, ...}
# @@current: #<AccountControllerTest:0xb192174>
#
# クラス変数を使う場合は、これらおよび未来の TestCase のクラス変数と
# 名前が被らないよう注意する必要あり
# setup とテストケース should の中とで情報をやりとりするのに
# 普通にインスタンス変数 @xxx を使うか、反則技でクラス変数 @@xxx を
# 使うのが良いか迷い中
#
# インスタンス変数を使うのが普通だが、
# - クラススコープからインスタンス変数にアクセスできなくて
# 残念に感じることがたまにある
# - 比較的多数のインスタンス変数がフレームワークによって
# 使われているため、命名の衝突が怖い
#
# クラス変数を使うのはかなり異端
# - 本来の目的からずれまくってるので完全に反則技
# - 初期化し忘れると直前のテストケースの値が残ってしまうのも問題
# - その代わり、どこからでもアクセスできるのがかなり便利?
@@valid_account_params = { name: "Foo Baa", email: "account@example.com", affiliation: "My institute", address: "My address", telephone: "+00-000-0000" } @@invalid_account_params = { name: '' } @@valid_registration_params = { gender: 1, membership: 1, student: false, receipt_address: 'My address', payaccount: 'My Account' } # インスタンス変数として以下が定義されるので、名前が # 被らないように注意が必要 # # インスタンス変数 利用時の記法 内容 # @__name__ @__name__ 現在実行中のテストのタイトルが入る # @__io__ # @passed # @_assertions # @fixture_cache # @fixture_connections # @loaded_fixtures # @tagged_logger # @_partials # @_templates # @_layouts # @_files # @request request #<ActionController::TestRequest> # @response response #<ActionController::TestResponse> # @controller @controller #<Controller under testing> # @routes @routes #<ActionDispatch::Routing::RouteSet> # @shoulda_context # @html_document html_document #<HTML::Document> # @assigns assigns @controller 内で定義されたインスタンス変数 } def clear_all ActionMailer::Base.deliveries.clear DatabaseRewinder.clean_all session.clear cookies.clear end # shoulda の redirect_to では、 # should redirect_to account_path # should redirect_to account_path(action: :edit) # should redirect_to url_for(controller: :account, action: :edit) # などとは書けないので、かわりに # should redirect_to("account_path"){ account_path } # should redirect_to("account_path(action: :edit)"){ account_path(action: :edit) } # should redirect_to("controller: :account, action: :edit"){ # @controller.url_for(controller: :account, action: :edit) } # としても良いのだけれど、より簡単に # should redirect_to_path :account # should redirect_to_path :account, action: :edit # should redirect_to_path controller: :account, action: :edit # などと書けるようにする def self.redirect_to_path(*arg) if arg.first.is_a? Symbol redirect_to_path_arg = arg.dup redirect_to_path_symbol = :"#{redirect_to_path_arg.shift}_path" if redirect_to_path_arg.empty? redirect_to(redirect_to_path_symbol){ __send__(redirect_to_path_symbol) } else redirect_to_path_arg_s =redirect_to_path_arg.inspect.gsub(/\A\[|\]\z/,'') redirect_to_path_arg_s.gsub!(/\A\{|\}\z/,'') if redirect_to_path_arg.count == 1 redirect_to("#{redirect_to_path_symbol}(#{redirect_to_path_arg_s})", &Proc.new { __send__(redirect_to_path_symbol, *redirect_to_path_arg) }) end else redirect_to_path_arg = arg.dup redirect_to_path_arg_s =redirect_to_path_arg.inspect.gsub(/\A\[|\]\z/,'') redirect_to_path_arg_s.gsub!(/\A\{|\}\z/,'') if redirect_to_path_arg.count == 1 redirect_to(redirect_to_path_arg_s){ @controller.url_for *redirect_to_path_arg } end end # 以下すべてを ja, en 両方のロケールで試す [:ja,:en].each do |locale| context "with locale #{locale}," do setup { request.env['HTTP_ACCEPT_LANGUAGE'] = locale.to_s } # ここからが本当のテスト内容 context "without login," do context "GET #new" do setup { get :new } should respond_with :success should render_template :new should_not set_the_flash end context 'GET #home' do setup { get :home } should redirect_to_path :account_login should set_the_flash should 'set session_intended_path to requested path' do # セッションキーは ApplicationController で # @session_intended_path="hogehoge" # として与えられているので、assigns を使って読み取る assert_equal @request.path, session[assigns(:session_intended_path)] end end context 'invalid POST #create' do setup { post :create, account: @@invalid_account_params } should "not create account" do assert_equal 0, Account.count end should render_template :new end context 'valid POST #create' do setup { post :create, account: @@valid_account_params } should "create account" do assert_equal 1, Account.count end should redirect_to_path :account_login should "send email to registered address" do assert_not ActionMailer::Base.deliveries.empty? email_sent = ActionMailer::Base.deliveries.last assert_equal @@valid_account_params[:email], email_sent.to end end end context "with autologin," do setup { clear_all @@account = Account.create!( @@valid_account_params.merge( password: Account.generate_new_password, auto_login: Account.generate_new_password ) ) cookies[assigns(:cookie_auto_login)] = [@@account.auto_login, @@account.email].join(':') } context 'GET #home' do setup { get :home } should respond_with :success should 'update autologin password at successful auto login' do assert_not_equal @@account.auto_login, assigns[:account].auto_login assert_equal assigns[:account].auto_login, cookies[assigns[:cookie_auto_login]].split(':',2)[0] end end context 'GET #new' do setup { get :new } should set_the_flash # already login should redirect_to_path :account end context 'GET #edit' do setup { get :edit } should respond_with :success end context 'POST #update' do setup { post :update, account: {name: "Updated Name"} } should 'update name' do account = Account.find_by_email(@@account.email) assert_equal "Updated Name", account.name end should set_the_flash # successfully updated should redirect_to_path :account end context 'DELETE #destroy' do setup { delete :destroy } should "delete account" do assert_equal 0, Account.count end should set_the_flash # successfully deleted should redirect_to_path :default end context 'with valid registration,' do setup { @@account.registration = Registration.create!(@@valid_registration_params) } context 'DELETE #destroy' do setup { delete :destroy } should "not delete account" do assert_equal 1, Account.count end should set_the_flash # can not delete should redirect_to_path :account end end end end end end
コメント†
Counter: 8955 (from 2010/06/03),
today: 1,
yesterday: 2