ActiveSupport_TestCase + shoulda によるテスト の履歴(No.1)
更新- 履歴一覧
- 差分 を表示
- 現在との差分 を表示
- ソース を表示
- ソフトウェア/rails/ActiveSupport_TestCase + shoulda によるテスト へ行く。
ActionController::TestCase + shoulda による Ruby on Rails コントローラのテスト†
- ActionController::TestCase は Rails 標準のコントローラテストフレームワーク
- shoulda は読みやすいテストケースを書くための gem
これらを使ってコントローラをテストするためのノウハウをメモとして残したい
いろいろ検討中†
まだちゃんとしたテストは書き始めたばかりなので全然やり方が定まってません。 このレベルの物をこんなところに晒すのも何なのですが、とりあえずメモとして書いちゃいます。
LANG:ruby(linenumber)
#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: 9245 (from 2010/06/03),
today: 2,
yesterday: 1