#はじめに
Railsチュートリアル第6版のテストをRSpecで書き直していく。
###目次
#Minitest
###Micropostテスト
require 'test_helper'
class MicropostTest < ActiveSupport::TestCase
def setup
@user = users(:michael)
@micropost = @user.microposts.build(content: "Lorem ipsum")
end
test "should be valid" do
assert @micropost.valid?
end
test "user id should be present" do
@micropost.user_id = nil
assert_not @micropost.valid?
end
test "content should be present" do
@micropost.content = " "
assert_not @micropost.valid?
end
test "content should be at most 140 characters" do
@micropost.content = "a" * 141
assert_not @micropost.valid?
end
test "order should be most recent first" do
assert_equal microposts(:most_recent), Micropost.first
end
test "associated microposts should be destroyed" do
@user.save
@user.microposts.create!(content: "Lorem ipsum")
assert_difference 'Micropost.count', -1 do
@user.destroy
end
end
end
###マイクロポスト用のfixture
orange:
content: "I just ate an orange!"
created_at: <%= 10.minutes.ago %>
user: michael
tau_manifesto:
content: "Check out the @tauday site by @mhartl: https://tauday.com"
created_at: <%= 3.years.ago %>
user: michael
cat_video:
content: "Sad cats are sad: https://youtu.be/PKffm2uI4dk"
created_at: <%= 2.hours.ago %>
user: michael
most_recent:
content: "Writing a short test"
created_at: <%= Time.zone.now %>
user: michael
<% 30.times do |n| %>
micropost_<%= n %>:
content: <%= Faker::Lorem.sentence(word_count: 5) %>
created_at: <%= 42.days.ago %>
user: michael
<% end %>
ants:
content: "Oh, is that what you want? Because that's how you get ants!"
created_at: <%= 2.years.ago %>
user: archer
zone:
content: "Danger zone!"
created_at: <%= 3.days.ago %>
user: archer
tone:
content: "I'm sorry. Your words made sense, but your sarcastic tone did not."
created_at: <%= 10.minutes.ago %>
user: lana
van:
content: "Dude, this van's, like, rolling probable cause."
created_at: <%= 4.hours.ago %>
user: lana
###Userプロフィール画面に対するテスト
require 'test_helper'
class UsersProfileTest < ActionDispatch::IntegrationTest
include ApplicationHelper
def setup
@user = users(:michael)
end
test "profile display" do
get user_path(@user)
assert_template 'users/show'
assert_select 'title', full_title(@user.name)
assert_select 'h1', text: @user.name
assert_select 'h1>img.gravatar'
assert_match @user.microposts.count.to_s, response.body
assert_select 'div.pagination'
@user.microposts.paginate(page: 1).each do |micropost|
assert_match micropost.content, response.body
end
end
end
###Micropostsコントローラの認可テスト
require 'test_helper'
class MicropostsControllerTest < ActionDispatch::IntegrationTest
def setup
@micropost = microposts(:orange)
end
test "should redirect create when not logged in" do
assert_no_difference 'Micropost.count' do
post microposts_path, params: { micropost: { content: "Lorem ipsum" } }
end
assert_redirected_to login_url
end
test "should redirect destroy when not logged in" do
assert_no_difference 'Micropost.count' do
delete micropost_path(@micropost)
end
assert_redirected_to login_url
end
test "should redirect destroy for wrong micropost" do
log_in_as(users(:michael))
micropost = microposts(:ants)
assert_no_difference 'Micropost.count' do
delete micropost_path(micropost)
end
assert_redirected_to root_url
end
end
###マイクロポストのUIに対する統合テスト
require 'test_helper'
class MicropostsInterfaceTest < ActionDispatch::IntegrationTest
def setup
@user = users(:michael)
end
test "micropost interface" do
log_in_as(@user)
get root_path
assert_select 'div.pagination'
# 無効な送信
assert_no_difference 'Micropost.count' do
post microposts_path, params: { micropost: { content: "" } }
end
assert_select 'div#error_explanation'
assert_select 'a[href=?]', '/?page=2' # 正しいページネーションリンク
# 有効な送信
content = "This micropost really ties the room together"
assert_difference 'Micropost.count', 1 do
post microposts_path, params: { micropost: { content: content } }
end
assert_redirected_to root_url
follow_redirect!
assert_match content, response.body
# 投稿を削除する
assert_select 'a', text: 'delete'
first_micropost = @user.microposts.paginate(page: 1).first
assert_difference 'Micropost.count', -1 do
delete micropost_path(first_micropost)
end
# 違うユーザーのプロフィールにアクセス(削除リンクがないことを確認)
get user_path(users(:archer))
assert_select 'a', text: 'delete', count: 0
end
end
#RSpec
###Micropostテスト
require 'rails_helper'
RSpec.describe Micropost, type: :model do
let!(:user) { FactoryBot.create(:user) }
let!(:tau_manifesto) {FactoryBot.create(:micropost, :tau_manifesto)}
let!(:cat_video) {FactoryBot.create(:micropost,:cat_video)}
let!(:most_recent) {FactoryBot.create(:micropost,:most_recent)}
let!(:micropost) {user.microposts.build(content: "Lorem ipsum")}
it "should be valid" do
expect(micropost).to be_valid
end
it "user id should be present" do
micropost.user_id = nil
expect(micropost).to_not be_valid
end
it "content should be present" do
micropost.content = " "
expect(micropost).to_not be_valid
end
it "content should be at most 140 characters" do
micropost.content = "a" * 141
expect(micropost).to_not be_valid
end
it "order should be most recent first" do
expect(most_recent).to eq Micropost.first
end
it "associated microposts should be destroyed" do
user.microposts.create!(content: "Lorem ipsum")
expect {
user.destroy
}.to change(Micropost, :count).by(-1)
end
end
let!
においてcreated_atがバラバラのmicropostを事前に用意しておく。
###マイクロポスト用のfactory
FactoryBot.define do
factory :micropost do
content {"I just ate an orange!"}
created_at {10.minutes.ago}
association :user
trait :tau_manifesto do
content {"Check out the @tauday site by @mhartl: https://tauday.com"}
created_at {3.years.ago}
end
trait :cat_video do
content {"Sad cats are sad: https://youtu.be/PKffm2uI4dk"}
created_at {2.hours.ago}
end
trait :most_recent do
content {"Writing a short test"}
created_at{Time.zone.now}
end
end
end
###Userプロフィール画面に対するテスト
require 'rails_helper'
include ApplicationHelper
RSpec.describe "UsersProfiles", type: :request do
let(:user) {FactoryBot.create(:user)}
before do
40.times do
user.microposts.create(content: Faker::Lorem.sentence(word_count: 5))
end
end
it "profile display" do
get user_path(user)
expect(response).to have_http_status(200)
assert_select "title", full_title(user.name)
assert_select "h1", text: user.name
assert_select "h1>img.gravatar"
assert_match user.microposts.count.to_s, response.body
assert_select "div.pagination"
user.microposts.paginate(page: 1).each do |micropost|
assert_match micropost.content, response.body
end
end
end
full_titleメソッドを使用する為に、include ApplicationHelperを記述しておく。
before do において、異なるcontentを持つmicropostを40個用意しておく(ページネーションを使いたいので30個以上にしておく)。
###Micropostsコントローラの認可テスト
require 'rails_helper'
RSpec.describe "Microposts", type: :request do
let!(:micropost) { FactoryBot.create(:micropost) }
let!(:user1) { FactoryBot.create(:user) }
it "should redirect create when not logged in" do
expect{
post microposts_path, params: { micropost: { content: "Lorem ipsum" } }
}.to_not change(Micropost, :count)
expect(response).to redirect_to login_path
end
it "should redirect destroy when not logged in" do
expect {
delete micropost_path(micropost)
}.to_not change(Micropost, :count)
expect(response).to redirect_to login_path
end
it "should redirect destroy for wrong micropost" do
log_in_as(user1)
expect {
delete micropost_path(micropost)
}.to_not change(Micropost, :count)
expect(response).to redirect_to root_path
end
end
it "should redirect destroy for wrong micropost" doにおいて、micropost作成者以外がログインしている状態で削除しようとすると失敗することをテストするため、let!
でuser1を作成しておく。
###マイクロポストのUIに対する統合テスト
require 'rails_helper'
RSpec.describe "MicropostsInterface", type: :request do
let!(:user) { FactoryBot.create(:user) }
let!(:user1) { FactoryBot.create(:user) }
before do
40.times do
user.microposts.create(content: Faker::Lorem.sentence(word_count: 5))
end
end
it "micropost interface" do
log_in_as(user)
get root_path
assert_select "div.pagination"
expect{
post microposts_path, params: { micropost: { content: "" } }
}.to_not change(Micropost, :count)
assert_select "div#error_explanation"
assert_select "a[href=?]", "/?page=2"
content = "This micropost really ties the room together"
expect{
post microposts_path, params: { micropost: { content: content } }
}.to change(Micropost, :count).by(1)
expect(response).to redirect_to root_path
follow_redirect!
#assert_match content, response.body
assert_select "a", text: "delete"
first_micropost = user.microposts.paginate(page: 1).first
expect{
delete micropost_path(first_micropost)
}.to change(Micropost, :count).by(-1)
get user_path(user1)
assert_select "a", text: "delete", count:0
end
end
#注意点
factoryにおいて
factory :micropost do
content {"I just ate an orange!"}
created_at {10.minutes.ago}
association :user
.
.
.
というように、associationでmicropostに関連づけられるuserを作成しているが、テスト内でlet!(:user) { FactoryBot.create(:user) }
とした場合、user factoryはシーケンスにより異なるメールアドレスを持つ別のユーザーが作成されることになる。例えばテスト内でuserとしてログインした状態でmicropostを削除しようとするとmicropostを作成したユーザーでないために失敗することになる。
よってページネーションのテストを行う際、
before do
40.times {FactoryBot.create(:micropost)}
end
ではなく
before do
40.times do
user.microposts.create(content: Faker::Lorem.sentence(word_count: 5))
end
end
と記述する必要がある。