この記事の基本的な方針
今回は別記事、ツイッター風Railsアプリ最短復習(忙しい人の流し読みで開発シリーズ)で作ったアプリの統合テストをします。
手を動かしながら読みたいようでしたら、以下でこのツイッター風Railsアプリを手に入れてください。
Terminal
$ git clone https://github.com/annaPanda8170/cheaptweet.git
$ bundle install
$ bundle exec rake db:create
$ bundle exec rake db:migrate
基本解説はしません。手順のみ示します。
想定する読み手
既に一度Railsアプリをチュートリアルやスクール等で作ったことがある方を想定しております。
Mac使用で、パソコンの環境構築は完了していることが前提です。
具体的な手順
①準備
Gemfile
# 省略
group :development, :test do
# 省略
gem 'rspec-rails'
gem 'factory_bot_rails'
end
group :development do
# 省略
gem 'spring-commands-rspec'
end
# 省略
※spring-commands-rspecは起動時間を速くするためのものでなくても問題はありません。
Terminal
$ bundle install
$ rails g rspec:install
$ rails g rspec:feature cheapTweet
$ rails g factory_bot:model user
$ rails g factory_bot:model tweet
$ bundle exec spring binstub rspec
control + c
$ rails s
.rspec
--format documentation
※これでRspecの出力が読みやすくなるそうです。
spec/rails_helper.rb
# 省略
require 'capybara/rspec'
include Warden::Test::Helpers
ここで空っぽのまま一度起動してみます。
Terminal
$ bundle exec rspec
Output
CheapTweets
add some scenarios (or delete) /Users/handaryouhei/Desktop/cheaptweet/spec/features/cheap_tweet_spec.rb (PENDING: Not yet implemented)
Pending: (Failures listed here are expected and do not affect your suite's status)
1) CheapTweets add some scenarios (or delete) /Users/handaryouhei/Desktop/cheaptweet/spec/features/cheap_tweet_spec.rb
# Not yet implemented
# ./spec/features/cheap_tweet_spec.rb:4
Finished in 0.0014 seconds (files took 2.21 seconds to load)
1 example, 0 failures, 1 pending
spec/factories/tweets.rb
FactoryBot.define do
factory :tweet do
text {"hello"}
association :user
end
end
spec/factories/users.rb
FactoryBot.define do
factory :user do
sequence(:nickname) { |n| "annaPanda#{n}" }
sequence(:email) { |n| "a#{n}@a" }
password {"111111"}
password_confirmation {"111111"}
end
end
②テスト構築
spec/features/cheap_tweet_spec.rb
require 'rails_helper'
RSpec.feature "CheapTweets", type: :feature do
scenario "新規登録するとログアウトが表示されているTOP画面に遷移する" do
visit root_path
click_link "会員登録"
fill_in "user_nickname", with: "annaPanda"
fill_in "user_email", with: "a@a"
fill_in "user_password", with: "111111"
fill_in "user_password_confirmation", with: "111111"
click_button "Sign up"
expect(page).to have_content 'ログアウト'
end
scenario "ログインするとログアウトが表示されているTOP画面に遷移する" do
user = FactoryBot.create(:user)
visit root_path
click_link "ログイン"
fill_in "user_email", with: "a1@a"
fill_in "user_password", with: "111111"
click_button "Log in"
expect(page).to have_content 'ログアウト'
end
scenario "非ログイン状態でTOP画面に遷移するとログアウトが表示されていない" do
visit root_path
expect(page).not_to have_content 'ログアウト'
end
scenario "投稿したらデータベースにtweetが一つ増える" do
user = FactoryBot.create(:user)
login_as(user, scope: :user)
visit root_path
expect{
click_link "投稿"
fill_in "tweet_text", with: "こんにちは"
click_button "投稿"
}.to change( Tweet.all, :count ).by(1)
end
scenario "自分で投稿したtweetをshowして編集するとindexに反映される" do
user = FactoryBot.create(:user)
login_as(user, scope: :user)
visit root_path
click_link "投稿"
fill_in "tweet_text", with: "こんにちは"
click_button "投稿"
click_link "こんにちは"
click_link '編集'
fill_in "tweet_text", with: "こんにちは!"
click_button '編集'
visit root_path
expect(page).to have_content 'こんにちは!'
end
scenario "自分以外が投稿したtweetをshowすれば編集ボタンが表示されない" do
tweet = FactoryBot.create(:tweet)
visit root_path
click_link "a"
expect(page).not_to have_content '編集'
end
scenario "自分で投稿したtweetをshowして削除ボタンを押せばデータベースのtweetが一つ減る" do
user = FactoryBot.create(:user)
login_as(user, scope: :user)
visit root_path
click_link "投稿"
fill_in "tweet_text", with: "こんばんは"
click_button "投稿"
click_link "こんばんは"
expect{
click_link "削除"
}.to change( Tweet.all, :count ).by(-1)
end
scenario "自分以外が投稿したtweetをshowすれば削除ボタンが表示されない" do
tweet = FactoryBot.create(:tweet)
visit root_path
click_link "hello"
expect(page).not_to have_content '削除'
end
scenario "ヘッダーの自分の名前をクリックすると自分の投稿一覧が表示される" do
tweet = FactoryBot.create(:tweet)
user = FactoryBot.create(:user)
login_as(user, scope: :user)
visit root_path
click_link "投稿"
fill_in "tweet_text", with: "おはよう"
click_button "投稿"
click_link "投稿"
fill_in "tweet_text", with: "さようなら"
click_button "投稿"
within 'header' do
click_link user.nickname
end
expect(page).to have_content 'おはよう'
expect(page).to have_content 'さようなら'
expect(page).not_to have_content 'hello'
end
scenario "TOP画面の投稿者をクリックするとそのユーザーの一覧が表示される" do
tweet = FactoryBot.create(:tweet)
user = FactoryBot.create(:user)
login_as(user, scope: :user)
visit root_path
click_link "投稿"
fill_in "tweet_text", with: "おはよう"
click_button "投稿"
click_link "投稿"
fill_in "tweet_text", with: "さようなら"
click_button "投稿"
click_link tweet.user.nickname
expect(page).not_to have_content 'おはよう'
expect(page).not_to have_content 'さようなら'
expect(page).to have_content 'hello'
end
scenario "コメントすると表示される" do
tweet = FactoryBot.create(:tweet)
user = FactoryBot.create(:user)
login_as(user, scope: :user)
visit root_path
click_link "hello"
fill_in "comment_text", with: "ハロー"
click_button "コメント"
expect(page).to have_content 'ハロー'
end
end
click_link
とclick_button
で指定しているのはテキストです。
fill_in
で指定しているのはidです。
have_content
で表示されているかを確認しています。
Terminal
$ bundle exec rspec
Output
CheapTweets
新規登録するとログアウトが表示されているTOP画面に遷移する
ログインするとログアウトが表示されているTOP画面に遷移する
非ログイン状態でTOP画面に遷移するとログアウトが表示されていない
投稿したらデータベースにtweetが一つ増える
自分で投稿したtweetをshowして編集するとindexに反映される
自分以外が投稿したtweetをshowすれば編集ボタンが表示されない
自分で投稿したtweetをshowして削除ボタンを押せばデータベースのtweetが一つ減る
自分以外が投稿したtweetをshowすれば削除ボタンが表示されない
ヘッダーの自分の名前をクリックすると自分の投稿一覧が表示される
TOP画面の投稿者をクリックするとそのユーザーの一覧が表示される
コメントすると表示される
Finished in 0.87206 seconds (files took 2.18 seconds to load)
11 examples, 0 failures
まとめ
読むだけなら割と直感的にいけると思います。
この統合テストさえ済ませていれば、コントローラは不要なのでは?という考えもあるようです。
モデルのテストとこの統合テストを行うことがRailsアプリのテストのスタンダードになるかもしれませんね。