User destroy tests
刪除使用者是一個危險的動作,所以最好寫個測試來確保刪除行為如預期。首先,先在 fixture 裡面設定一個使用者為管理員:
test/fixtures/users.yml
michael:
name: Michael Example
email: michael@example.com
password_digest: <%= User.digest('password') %>
admin: true
處理有關 action 的測試,通常都會寫在 controller test 裡面,也就是 Users controller test,然後使用 delete 方法向 destroy action 處理 DELETE 請求。我們要確認兩件事:
- 如果使用者未登入,會導向登入頁面
- 第二,如果登入的使用者不是管理員,會導向到首頁
程式碼如下:
test/controllers/users_controller_test.rb
require 'test_helper'
class UsersControllerTest < ActionController::TestCase
def setup
@user = users(:michael)
@other_user = users(:archer)
end
.
.
.
test "should redirect destroy when not logged in" do
assert_no_difference 'User.count' do
delete :destroy, id: @user
end
assert_redirected_to login_url
end
test "should redirect destroy when logged in as a non-admin" do
log_in_as(@other_user)
assert_no_difference 'User.count' do
delete :destroy, id: @user
end
assert_redirected_to root_url
end
end
注意,上述程式碼使用了 assert_no_difference 確認使用者的數量沒有變化。
上面的測試是確認已登入但沒有權限的使用者不能刪除使用者,不過我們也想檢查管理員可以成功的使用「delete」連結刪除使用者。因為「delete」連結是在使用者列表顯示,所以我們要在 users_index_test.rb 裡面增加這個測試。這個測試的技巧在於,當管理員點擊「delete」連結後,檢查使用者的數量:
assert_difference 'User.count', -1 do
delete user_path(@other_user)
end
也就是確認向相對應的位址發送 DELETE 請求之後,透過 User.count,加上參數 -1 ,藉此比較刪除前後的使用者數量的變化。
程式碼如下,包含了對管理員以及沒有管理權限的使用者的測試:
test/integration/users_index_test.rb
require 'test_helper'
class UsersIndexTest < ActionDispatch::IntegrationTest
def setup
@admin = users(:michael)
@non_admin = users(:archer)
end
test "index as admin including pagination and delete links" do
log_in_as(@admin)
get users_path
assert_template 'users/index'
assert_select 'div.pagination'
first_page_of_users = User.paginate(page: 1)
first_page_of_users.each do |user|
assert_select 'a[href=?]', user_path(user), text: user.name
unless user == @admin
assert_select 'a[href=?]', user_path(user), text: 'delete'
end
end
assert_difference 'User.count', -1 do
delete user_path(@non_admin)
end
end
test "index as non-admin" do
log_in_as(@non_admin)
get users_path
assert_select 'a', text: 'delete', count: 0
end
end
上述程式碼也檢查每個使用者都會有「delete」連結,然後如果是管理員就不做這項檢查(因為管理員本身不會顯示「delete」)。
最後執行測試,應該會成功(Green):
$ bundle exec rake test