はじめに
Railsでアプリケーションを開発する際、品質を担保するためにテストは欠かせません。その中でも、RSpecは多くの開発者に愛用されているテストフレームワークです。
今回は、RSpecを使ったRailsアプリケーションのテスト方法について、実践的な視点から解説していきます。
コントローラースペック
アクションのテスト
コントローラーのアクションのテストでは、リクエストが正しく処理され、適切なレスポンスやビューが返されるかを確認します。以下に、典型的なコントローラのアクションテストの例を示します。
まず、UsersController
を定義します。
app/controllers/users_controller.rb
class UsersController < ApplicationController
def index
@users = User.all
end
def show
@user = User.find(params[:id])
end
def new
@user = User.new
end
def create
@user = User.new(user_params)
if @user.save
redirect_to @user, notice: 'User was successfully created.'
else
render :new
end
end
def edit
@user = User.find(params[:id])
end
def update
@user = User.find(params[:id])
if @user.update(user_params)
redirect_to @user, notice: 'User was successfully updated.'
else
render :edit
end
end
def destroy
@user = User.find(params[:id])
@user.destroy
redirect_to users_url, notice: 'User was successfully destroyed.'
end
private
def user_params
params.require(:user).permit(:name, :email, :password)
end
end
次に、RSpecを使ってこれらのアクションをテストします。
spec/controllers/users_controller_spec.rb
require 'rails_helper'
RSpec.describe UsersController, type: :controller do
let(:valid_attributes) { { name: 'Alice', email: 'alice@example.com', password: 'password' } }
let(:invalid_attributes) { { name: nil, email: 'alice@example.com', password: 'password' } }
describe 'GET #index' do
it 'returns a success response' do
User.create!(valid_attributes)
get :index
expect(response).to be_successful
expect(assigns(:users)).to eq(User.all)
end
end
describe 'GET #show' do
it 'returns a success response' do
user = User.create!(valid_attributes)
get :show, params: { id: user.to_param }
expect(response).to be_successful
expect(assigns(:user)).to eq(user)
end
end
describe 'GET #new' do
it 'returns a success response' do
get :new
expect(response).to be_successful
expect(assigns(:user)).to be_a_new(User)
end
end
describe 'POST #create' do
context 'with valid params' do
it 'creates a new User' do
expect {
post :create, params: { user: valid_attributes }
}.to change(User, :count).by(1)
end
it 'redirects to the created user' do
post :create, params: { user: valid_attributes }
expect(response).to redirect_to(User.last)
expect(flash[:notice]).to eq('User was successfully created.')
end
end
context 'with invalid params' do
it 'does not create a new User' do
expect {
post :create, params: { user: invalid_attributes }
}.not_to change(User, :count)
end
it 'renders the new template' do
post :create, params: { user: invalid_attributes }
expect(response).to render_template(:new)
end
end
end
describe 'GET #edit' do
it 'returns a success response' do
user = User.create!(valid_attributes)
get :edit, params: { id: user.to_param }
expect(response).to be_successful
expect(assigns(:user)).to eq(user)
end
end
describe 'PATCH #update' do
context 'with valid params' do
let(:new_attributes) { { name: 'Bob' } }
it 'updates the requested user' do
user = User.create!(valid_attributes)
patch :update, params: { id: user.to_param, user: new_attributes }
user.reload
expect(user.name).to eq('Bob')
end
it 'redirects to the user' do
user = User.create!(valid_attributes)
patch :update, params: { id: user.to_param, user: new_attributes }
expect(response).to redirect_to(user)
expect(flash[:notice]).to eq('User was successfully updated.')
end
end
context 'with invalid params' do
it 'does not update the user' do
user = User.create!(valid_attributes)
patch :update, params: { id: user.to_param, user: invalid_attributes }
expect(response).to render_template(:edit)
end
end
end
describe 'DELETE #destroy' do
it 'destroys the requested user' do
user = User.create!(valid_attributes)
expect {
delete :destroy, params: { id: user.to_param }
}.to change(User, :count).by(-1)
end
it 'redirects to the users list' do
user = User.create!(valid_attributes)
delete :destroy, params: { id: user.to_param }
expect(response).to redirect_to(users_url)
expect(flash[:notice]).to eq('User was successfully destroyed.')
end
end
end
GET #index
get :index
を実行し、レスポンスが成功(200 OK)であることを確認します。@users
インスタンス変数に全てのユーザーが正しく割り当てられていることを確認します。
GET #show
- ユーザーが存在する場合、
get :show, params: { id: user.to_param }
を実行し、レスポンスが成功(200 OK)であることを確認します。 @user
インスタンス変数に該当するユーザーが正しく割り当てられていることを確認します。- ユーザーが存在しない場合、レスポンスが
404 Not Found
であることを確認します。
- ユーザーが存在する場合、
GET #new
get :new
を実行し、レスポンスが成功(200 OK)であることを確認します。@user
インスタンス変数に新しいユーザーオブジェクトが割り当てられていることを確認します。
POST #create
- 有効なパラメータの場合 (with valid params)
- 新しいユーザーが作成されることを確認します。
- 作成後、ユーザーの詳細ページにリダイレクトされることを確認します。
- 無効なパラメータの場合 (with invalid params)
- 新しいユーザーが作成されないことを確認します。
- 新規作成ページが再表示されることを確認します。
- 有効なパラメータの場合 (with valid params)
GET #edit
get :edit, params: { id: user.to_param }
を実行し、レスポンスが成功(200 OK)であることを確認します。@user
インスタンス変数に該当するユーザーが正しく割り当てられていることを確認します。
PATCH #update
- 有効なパラメータの場合 (with valid params)
- ユーザーが正しく更新されることを確認します。
- 更新後、ユーザーの詳細ページにリダイレクトされることを確認します。
- 無効なパラメータの場合 (with invalid params)
- ユーザーが更新されないことを確認します。
- 編集ページが再表示されることを確認します。
- 有効なパラメータの場合 (with valid params)
DELETE #destroy
delete :destroy, params: { id: user.to_param }
を実行し、該当するユーザーが削除されることを確認します。- 削除後、ユーザーリストページにリダイレクトされることを確認します。
まとめ
RSpecを使いこなすことで、Railsアプリケーションの品質を大幅に向上させることができます。ただし、テストの書きすぎには注意が必要です。重要な機能や複雑なロジックに焦点を当て、バランスの取れたテスト戦略を立てることが大切です。
また、CIツールと組み合わせることで、継続的にテストを実行し、問題を早期に発見することができます。例えば、GitHubActionsを使えば、プッシュやプルリクエスト時に自動的にテストを実行できます。
Railsアプリケーション開発において、RSpecは強力な味方となります。ぜひ、日々の開発に取り入れて、より堅牢なアプリケーション作りを目指してください。