#はじめに
Railsチュートリアル第6版のテストをRSpecで書き直していく。
###目次
#Minitest
###編集に対するテスト
test/integration/users_edit_test.rb
require 'test_helper'
class UsersEditTest < ActionDispatch::IntegrationTest
def setup
@user = users(:michael)
end
test "unsuccessful edit" do
log_in_as(@user)
get edit_user_path(@user)
assert_template 'users/edit'
patch user_path(@user), params: { user: { name: "",
email: "foo@invalid",
password: "foo",
password_confirmation: "bar" } }
assert_template 'users/edit'
end
test "successful edit" do
log_in_as(@user)
get edit_user_path(@user)
assert_template 'users/edit'
name = "Foo Bar"
email = "foo@bar.com"
patch user_path(@user), params: { user: { name: name,
email: email,
password: "",
password_confirmation: "" } }
assert_not flash.empty?
assert_redirected_to @user
@user.reload
assert_equal name, @user.name
assert_equal email, @user.email
end
test "successful edit with friendly forwarding" do
get edit_user_path(@user)
log_in_as(@user)
assert_redirected_to edit_user_url(@user)
name = "Foo Bar"
email = "foo@bar.com"
patch user_path(@user), params: { user: { name: name,
email: email,
password: "",
password_confirmation: "" } }
assert_not flash.empty?
assert_redirected_to @user
@user.reload
assert_equal name, @user.name
assert_equal email, @user.email
end
end
###editとupdateアクションの保護に対するテスト
test/controllers/users_controller_test.rb
require 'test_helper'
class UsersControllerTest < ActionDispatch::IntegrationTest
def setup
@user = users(:michael)
@other_user = users(:archer)
end
test "should get new" do
get signup_path
assert_response :success
end
test "should redirect index when not logged in" do
get users_path
assert_redirected_to login_url
end
test "should redirect edit when not logged in" do
get edit_user_path(@user)
assert_not flash.empty?
assert_redirected_to login_url
end
test "should redirect update when not logged in" do
patch user_path(@user), params: { user: { name: @user.name,
email: @user.email } }
assert_not flash.empty?
assert_redirected_to login_url
end
test "should redirect edit when logged in as wrong user" do
log_in_as(@other_user)
get edit_user_path(@user)
assert flash.empty?
assert_redirected_to root_url
end
test "should redirect update when logged in as wrong user" do
log_in_as(@other_user)
patch user_path(@user), params: { user: { name: @user.name,
email: @user.email } }
assert flash.empty?
assert_redirected_to root_url
end
test "should redirect destroy when not logged in" do
assert_no_difference 'User.count' do
delete user_path(@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 user_path(@user)
end
assert_redirected_to root_url
end
end
###fixture
test/fixtures/users.yml
michael:
name: Michael Example
email: michael@example.com
password_digest: <%= User.digest('password') %>
admin: true
archer:
name: Sterling Archer
email: duchess@example.gov
password_digest: <%= User.digest('password') %>
lana:
name: Lana Kane
email: hands@example.gov
password_digest: <%= User.digest('password') %>
malory:
name: Malory Archer
email: boss@example.gov
password_digest: <%= User.digest('password') %>
<% 30.times do |n| %>
user_<%= n %>:
name: <%= "User #{n}" %>
email: <%= "user-#{n}@example.com" %>
password_digest: <%= User.digest('password') %>
<% end %>
###UsersIndexのテスト
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
#RSpec
###編集に対するテスト
spec/system/users_edit_spec.rb
require 'rails_helper'
RSpec.describe "UsersEdits", type: :system do
let(:user) {FactoryBot.create(:user)}
it "unsuccessful edit" do
visit login_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Log in"
click_on "Setting"
expect(page).to have_current_path edit_user_path(user)
fill_in "Name", with: ""
fill_in "Email", with: "user@invalid"
fill_in "Password", with: "foo"
fill_in "Confirmation", with: "bar"
click_on "Save changes"
expect(page).to have_current_path user_path(user)
end
it "successful edit" do
visit login_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Log in"
click_on "Setting"
expect(page).to have_current_path edit_user_path(user)
fill_in "Name", with: "Foo Bar"
fill_in "Email", with: "foo@bar.com"
fill_in "Password", with: ""
fill_in "Confirmation", with: ""
click_on "Save changes"
expect(page).to have_content("Profile updated")
expect(page).to have_current_path user_path(user)
user.reload
expect(user.name).to eq "Foo Bar"
expect(user.email).to eq "foo@bar.com"
end
it "successful edit with friendly forwarding" do
visit edit_user_path(user)
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Log in"
expect(page).to have_current_path edit_user_path(user)
fill_in "Name", with: "Foo Bar"
fill_in "Email", with: "foo@bar.com"
fill_in "Password", with: ""
fill_in "Confirmation", with: ""
click_on "Save changes"
expect(page).to have_content("Profile updated")
expect(page).to have_current_path user_path(user)
user.reload
expect(user.name).to eq "Foo Bar"
expect(user.email).to eq "foo@bar.com"
end
end
###editとupdateアクションの保護に対するテスト
spec/requests/users_spec.rb
require 'rails_helper'
RSpec.describe "Users", type: :request do
before do
@user = FactoryBot.create(:user)
@noadmin_user = FactoryBot.create(:user, :noadmin)
end
it "returns http success" do
get signup_path
expect(response).to have_http_status(:success)
end
it "should redirect index when not logged in" do
get users_path
expect(response).to redirect_to login_path
end
it "should redirect edit when not logged in" do
get edit_user_path(@user)
expect(flash[:danger]).to eq "Please log in."
expect(response).to redirect_to login_url
end
it "should redirect update when not logged in" do
patch user_path(@user), params: { user: { name: @user.name,
email: @user.email } }
expect(flash[:danger]).to eq "Please log in."
expect(response).to redirect_to login_url
end
it "should redirect edit when logged in as wrong user" do
log_in_as(@noadmin_user)
get edit_user_path(@user)
expect(flash[:danger]).to eq nil
expect(response).to redirect_to root_url
end
it "should redirect update when logged in as wrong user" do
log_in_as(@noadmin_user)
patch user_path(@user), params: { user: { name: @user.name,
email: @user.email } }
expect(flash[:danger]).to eq nil
expect(response).to redirect_to root_url
end
it"should redirect destroy when not logged in" do
expect {
delete user_path(@user)
}.to_not change(User, :count)
expect(response).to redirect_to login_url
end
it "should redirect destroy when logged in as a non-admin" do
log_in_as(@noadmin_user)
expect {
delete user_path(@user)
}.to_not change(User, :count)
expect(response).to redirect_to root_url
end
end
let
を使用してユーザーを遅延読み込みしてしまうと、最後の二つのテスト内のexpect {delete user_path(@user)}.to_not change(User, :count)
において結果的にユーザー数が変わってしまいエラーになるため今回はbefore
で代用。
###factory
spec/factories/users.rb
FactoryBot.define do
factory :user do
name {"Michael Example"}
sequence(:email) { |n| "test#{n}@example.com" }
password {"password"}
password_confirmation {"password"}
admin {true}
trait :noadmin do
admin {false}
end
trait :users do
sequence(:name) { |n| "User#{n}" }
sequence(:email) { |n| "testusers#{n}@example.com" }
admin {false}
end
end
end
traitを使用し、adminがfalseである非管理者のnoadmin、シーケンスを用いたnameとemailを持ち非管理者のusersを作成。
###UsersIndexのテスト
spec/requests/users_index_spec.rb
require 'rails_helper'
RSpec.describe "UsersIndex", type: :request do
before do
30.times {FactoryBot.create(:user, :users)}
@admin_user = FactoryBot.create(:user)
@noadmin_user = FactoryBot.create(:user, :noadmin)
end
it "index as admin including pagination and delete links" do
log_in_as(@admin_user)
get users_path
expect(response).to have_http_status(200)
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: "delete"
unless user == @admin_user
assert_select "a[href=?]", user_path(user), text: "delete"
end
end
expect {
delete user_path(@noadmin_user)
}.to change(User, :count).by(-1)
end
it "index as non-admin" do
log_in_as(@noadmin_user)
get users_path
assert_select "a", text: "delete", count: 0
end
end
editとupdateアクションの保護に対するテストと同理由で、let
をbefore
で代用。before do
内において、factoryで作成したusersを三十人分複製し、ページネーションのテストに使用する。