0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【RSpec】Railsチュートリアル第6版 第11章

Last updated at Posted at 2021-11-05

#はじめに
Railsチュートリアル第6版のテストをRSpecで書き直していく。

###目次

#Minitest

###fixtureのユーザーを有効にしておく

test/fixtures/users.yml
michael:
  name: Michael Example
  email: michael@example.com
  password_digest: <%= User.digest('password') %>
  admin: true
  activated: true
  activated_at: <%= Time.zone.now %>

archer:
  name: Sterling Archer
  email: duchess@example.gov
  password_digest: <%= User.digest('password') %>
  activated: true
  activated_at: <%= Time.zone.now %>

lana:
  name: Lana Kane
  email: hands@example.gov
  password_digest: <%= User.digest('password') %>
  activated: true
  activated_at: <%= Time.zone.now %>

malory:
  name: Malory Archer
  email: boss@example.gov
  password_digest: <%= User.digest('password') %>
  activated: true
  activated_at: <%= Time.zone.now %>

<% 30.times do |n| %>
user_<%= n %>:
  name:  <%= "User #{n}" %>
  email: <%= "user-#{n}@example.com" %>
  password_digest: <%= User.digest('password') %>
  activated: true
  activated_at: <%= Time.zone.now %>
<% end %>

###アカウント有効化のプレビューメソッド

test/mailers/previews/user_mailer_preview.rb
# Preview all emails at http://localhost:3000/rails/mailers/user_mailer
class UserMailerPreview < ActionMailer::Preview

  # Preview this email at
  # http://localhost:3000/rails/mailers/user_mailer/account_activation
  def account_activation
    user = User.first
    user.activation_token = User.new_token
    UserMailer.account_activation(user)
  end

  # Preview this email at
  # http://localhost:3000/rails/mailers/user_mailer/password_reset
  def password_reset
    UserMailer.password_reset
  end
end

###Userメイラーのテスト

test/mailers/user_mailer_test.rb
test "account_activation" do
    user = users(:michael)
    user.activation_token = User.new_token
    mail = UserMailer.account_activation(user)
    assert_equal "Account activation", mail.subject
    assert_equal [user.email], mail.to
    assert_equal ["noreply@example.com"], mail.from
    assert_match user.name,               mail.body.encoded
    assert_match user.activation_token,   mail.body.encoded
    assert_match CGI.escape(user.email),  mail.body.encoded
  end
end

###Userテスト内の抽象化したauthenticated?メソッド

test/models/user_test.rb
require 'test_helper'

class UserTest < ActiveSupport::TestCase

 def setup
   @user = User.new(name: "Example User", email: "user@example.com",
                    password: "foobar", password_confirmation: "foobar")
 end
 .
 .
 .
 test "authenticated? should return false for a user with nil digest" do
   assert_not @user.authenticated?(:remember, '')
 end
end

###ユーザー登録のテストにアカウント有効化を追加する

test/integration/users_signup_test.rb
require 'test_helper'

class UsersSignupTest < ActionDispatch::IntegrationTest

  def setup
    ActionMailer::Base.deliveries.clear
  end

  test "invalid signup information" do
    get signup_path
    assert_no_difference 'User.count' do
      post users_path, params: { user: { name:  "",
                                         email: "user@invalid",
                                         password:              "foo",
                                         password_confirmation: "bar" } }
    end
    assert_template 'users/new'
    assert_select 'div#error_explanation'
    assert_select 'div.field_with_errors'
  end

  test "valid signup information with account activation" do
    get signup_path
    assert_difference 'User.count', 1 do
      post users_path, params: { user: { name:  "Example User",
                                         email: "user@example.com",
                                         password:              "password",
                                         password_confirmation: "password" } }
    end
    assert_equal 1, ActionMailer::Base.deliveries.size
    user = assigns(:user)
    assert_not user.activated?
    # 有効化していない状態でログインしてみる
    log_in_as(user)
    assert_not is_logged_in?
    # 有効化トークンが不正な場合
    get edit_account_activation_path("invalid token", email: user.email)
    assert_not is_logged_in?
    # トークンは正しいがメールアドレスが無効な場合
    get edit_account_activation_path(user.activation_token, email: 'wrong')
    assert_not is_logged_in?
    # 有効化トークンが正しい場合
    get edit_account_activation_path(user.activation_token, email: user.email)
    assert user.reload.activated?
    follow_redirect!
    assert_template 'users/show'
    assert is_logged_in?
  end
end

#RSpec

###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}
    activated {true}
    activated_at {Time.zone.now}

    trait :noadmin do
      admin {false}
    end

    trait :noactivated do
      admin {false}
      activated {false}
      activated_at { nil }
    end

    trait :users do
      sequence(:name) { |n| "User#{n}" } 
      sequence(:email) { |n| "testusers#{n}@example.com" }
      admin {false}
    end

  end
end

userのactivatedをtrueにしておく。
また、ユーザー登録のテストにアカウント有効化を追加するにおいて使用する無効なユーザーであるnoactivatedユーザーを作成しておく。

###アカウント有効化のプレビューメソッド

spec/mailers/previews/user_mailer_preview.rb
# Preview all emails at http://localhost:3000/rails/mailers/user_mailer
class UserMailerPreview < ActionMailer::Preview

  # Preview this email at http://localhost:3000/rails/mailers/user_mailer/account_activation
  def account_activation
    user = User.first
    user.activation_token = User.new_token
    UserMailer.account_activation(user)
  end

  # Preview this email at http://localhost:3000/rails/mailers/user_mailer/password_reset
  def password_reset
    UserMailer.password_reset
  end

end

###Userメイラーのテスト

spec/mailers/user_mailer_spec.rb
RSpec.describe UserMailer, type: :mailer do
  
  describe "account_activation" do

    let(:user) { FactoryBot.create(:user) }
    let(:mail) { UserMailer.account_activation(user) }
    
    it "renders the headers" do
      expect(mail.subject).to eq("Account activation")
      expect(mail.to).to eq([user.email])
      expect(mail.from).to eq(["noreply@example.com"])
    end

    it "renders the body" do
      expect(mail.body.encoded).to match(user.name)
      expect(mail.body.encoded).to match(user.activation_token)
      expect(mail.body.encoded).to match(CGI.escape(user.email))
    end

  end

end

FactoryBotでユーザーを作成した際、Userモデルのbefore_create :create_activation_digestが実行されるため、user.activation_token = User.new_tokenは記述しなくて良い。

###Userテスト内の抽象化したauthenticated?メソッド

spec/models/user_spec.rb
require 'rails_helper'

RSpec.describe User, type: :model do

  before do
    @user = User.new(name: "Example User", email: "user@example.com",
                     password: "foobar", password_confirmation: "foobar")
  end
  .
  .
  .
  it "authenticated? should return false for a user with nil digest" do
    expect(@user.authenticated?(:remember, "")).to be_falsy
  end

end

###ユーザー登録のテストにアカウント有効化を追加する

spec/requests/users_signups_spec.rb
require 'rails_helper'

RSpec.describe "UsersSignups", type: :request do

  before do
    ActionMailer::Base.deliveries.clear
  end

  let(:user) { FactoryBot.attributes_for(:user) }
  let(:noactivateduser) { FactoryBot.create(:user, :noactivated) }


  it "valid signup information" do
    expect {
      post users_path, params: { user: user }
    }.to change(User, :count).by(1)
    expect(response).to redirect_to root_url
    expect(is_logged_in?).to be_falsy
  end

  it "valid signup information with account activation" do
    expect(noactivateduser).to_not be_activated
    log_in_as(noactivateduser)
    expect(is_logged_in?).to be_falsy
    get edit_account_activation_path("invalid token", email: noactivateduser.email)
    expect(is_logged_in?).to be_falsy
    get edit_account_activation_path(noactivateduser.activation_token, email: "wrong")
    expect(is_logged_in?).to be_falsy
    get edit_account_activation_path(noactivateduser.activation_token, email: noactivateduser.email)
    assert noactivateduser.reload.activated?
    expect(noactivateduser).to be_activated
    expect(response).to redirect_to user_path(noactivateduser)
    expect(is_logged_in?).to be_truthy
  end

end

第8章において作成したrequest specに記述していく。
第8章では、is logges_in?メソッドを使用するためにsystem specの一部をrequest specの*"valid signup information"に移動させたが、その中身を今回の内容に合わせて一部変更している。
注意すべきなのが、
"valid signup information"*を成功させるためには、FactoryBot.attributes_forでユーザーを作成する必要があるが、実際に、無効なユーザーのデータを使用するためにはFactoryBot.createで作成していなければならないため、今回は二つのテストに分けて記述している。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?