はじめに
Railsで個人開発しているのですが、Testというものをあまり書いたことがなかったので、書いてみようと思い書きはじめてみたものの、思いの外まとまっている記事がなかったの備忘録ついでにまとめてみました。
(*テスト初心者なので、間違い等あったらご指摘いただけると幸いです。)
環境
- macOS High Sierra 10.13.6
- Ruby 2.5.1
- Ruby on Rails 5.1.4
- gem
- rspec-rails
- factory_bot_rails
- faker
- devise *ログイン周りをこれで実装しているためテスト実装前に設定が必要
RSpecとは
Ruby/Ruby on Railsで作ったクラスやメソッドが正常に動作するかをテストするためのドメイン特化言語 (DSL)のこと。
FactoryBotとは
テスト用のデータを作成してくれるツール。
もともとは、FactoryGirlという名前だったが、その名前に対して不快感を感じる人が多く、そのためFactoyBotという名前になったそう。
参考URL
【翻訳】"Factory Girl"が"Factory Bot"に変わった理由(と移行手順)
Fakerとは
様々なダミーデータを生成してくれるツール。
実際にやってみた
Relation
User has_many Groups
Group belongs_to User
事前準備
gemのインストール、RSpecのインストール
group :development, :test do
gem 'rspec-rails', '~> 3.7'
gem 'factory_bot_rails'
gem 'faker'
end
$ bundle install
RSpecのインストール
$ bundle exec rails generate rspec:install
FactoryBotの設定
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
end
上記は、以下のようにrspecのテストコード中でFactoryBotのメソッドを使用する際、
上述のコードを加えることで、以下のようにrspecのテストコード中でFactoryBotのメソッドを使用する際に、名前空間を指定する必要がなくなります。
user = FactoryBot.create(:user)
↓
user = create(:user)
超便利。
ちなみに、
今回、Deviseを採用しているので、以下の設定も必要。
Deviseを使っている方は、こちらを参考に設定してみてください!
参考URL
rspecのテスト環境でdeviseにログインする方法【rails】
テストデータの作成
FactoryBot.define do
factory :user do
password = Faker::Internet.password(8)
nickname { Faker::Name.last_name }
email { Faker::Internet.free_email }
password { password }
password_confirmation { password }
end
end
FactoryBot.define do
factory :group do
name { "名前" }
host_name { "主催者の名前" }
regulation { "参加条件" }
explanation { "説明" }
user
end
end
require 'rails_helper'
RSpec.describe Public::GroupsController, type: :controller do
let!(:user) { create(:user) }
let!(:group) { create(:group) }
let!(:group_attributes) { attributes_for(:group) }
describe 'GET #index' do
before do
login_user user
end
it "responds successfully" do
get :index
expect(response).to be_success
end
it "gets index" do
get :index
expect(response.status).to eq(200)
end
end
describe 'GET #show' do
before do
login_user user
end
it "assigns the requested group to @group" do
get :show, params: { id: group.id }
expect(response.status).to eq(200)
end
end
describe 'GET #new' do
before do
login_user user
end
it 'assigns new @group' do
expect(response.status).to eq(200)
end
end
describe 'Post #create' do
before do
login_user user
end
context "when @group can be saved" do
it "saves group on DB" do
expect do
post :create, params: { group: group_attributes }
end.to change(Group, :count).by(1)
end
end
context "when @group can not be saved" do
it "doesn't save group on DB" do
expect do
post :create, params: {
group: {
name: "",
host_name: "サンプル",
regulation: "サンプル",
explanation: "サンプル"
}
}
end.to change(Group, :count).by(0)
end
end
end
describe 'GET #edit' do
before do
login_user user
end
it "assigns the requested group to @group" do
get :edit, params: { id: group.id }
expect(response.status).to eq(200)
end
end
describe 'PATCH #update' do
before do
login_user user
end
let(:update_attributes) do
{ regulation: 'アップデート', explanation: 'アップデート' }
end
it 'saves updated group' do
expect do
patch :update, params: { id: group.id, group: update_attributes }, session: {}
end.to change(Group, :count).by(0)
end
it 'updates updated group' do
patch :update, params: { id: group.id, group: update_attributes }
group.reload
end
end
describe 'DELETE #destroy' do
before do
login_user user
end
it 'deletes group' do
expect do
delete :destroy, params: { id: group.id }, session: {}
end.to change(Group, :count).by(0)
end
end
end
解説
今回は、以下の定義済みのアクションのテストを実装
- index
- show
- new
- create
- edit
- destroy
- update
* resourcesで定義されるアクションすべてですね。
ソースコードを上から順に、
let!(:user) { create(:user) }
let!(:group) { create(:group, user: user) }
let!(:group_attributes) { attributes_for(:group) }
letを使うことで、それぞれ変数を定義しています。
定義することで、それぞれexample内でテストデータを定義する必要がなくなり、コード量が減らせ、可読性も高まります。letで定義された変数の状態は、他のテストに引き継がれないのがミソ!!
上記はそれぞれテスト内で、
user
group
group_attributes
として使うことができます。
index
まずは、indexアクションから。
describeは、テストの説明が入ります。
以下のように使います。
describe '説明' do
・・・
end
今後も出てくるので、必須です!
before do
login_user user
end
こちらは、describe内のテストが実行される前に、実行する処理になります。
(login_userは、rspecのテスト環境でdeviseにログインする方法【rails】 で設定した、controller_macros.rbに定義されています。)
it "responds successfully" do
get :index
expect(response).to be_success
end
it "get index" do
get :index
expect(response.status).to eq(200)
end
上は、indexに対し、getでアクセスしたときに、期待したresponseがbe_successであったかどうか、ということです。
下は、indexに対し、getでアクセスしたときに、正常なレスポンス(200番)が返ってきているかをテストしています。
show
describe 'GET #show' do
before do
login_user user
end
it "responds successfully" do
get :show, params: { id: group.id }
expect(response).to be_success
end
it "assigns the requested group to @group" do
get :show, params: { id: group.id }
expect(response.status).to eq(200)
end
end
上は、showに対しgetでアクセスしたときに、期待したresponseがbe_successであったかどうか、ということです。
下は、showに対しgetでアクセスしたときに、正常なレスポンス(200番)が返ってきているかをテストしています。
*indexとの違いは、showアクションでは、id(ここでは、groupのid)が必要なので、paramsで設定する必要があります。
長くなってきたので、一旦ここまで。
次回は、newからスタート
つづく