いよいよ大事なテストを書いていきます。
この記事では、テスト項目について書きます。
Rspecの基礎的な書き方については対象外とします。
こちらの記事でdeviceを実装した前提です。
記事の完成データはこちら
https://github.com/daisuke131/devise_token_auth_rspec
必要なファイルを作成
$ bundle exec rails g rspec:model user
これにより、spec/models/user_spec.rb
とspec/factories/users.rb
が生成されます。
続いてspec/requests/api/v1/auth/registrations_spec.rb
を作成します
これでファイルが揃いました。
factoriesファイル修正
FactoryBot.define do
factory :user do
name { Faker::Name.name }
sequence(:email) { |n| "#{n}_" + Faker::Internet.email }
password { Faker::Internet.password(8) }
end
end
emailは一意テストをするので重複しないよう念の為、emailの最初に番号をつけてます。
モデルのテスト
テスト項目
ここではUserモデルの保存処理のテストを行います。
- 全カラムの値を指定してるとき、レコードが作成されること
- emailを指定していないとき、エラーになること
- passwordを指定していないとき、エラーになること
- すでに保存されているemailを指定したとき、エラーになること
require 'rails_helper'
RSpec.describe User, type: :model do
describe "validates presence" do
context "全カラムの値を指定しているとき" do
let(:user) { create(:user) }
it "userのレコードが作成される" do
expect(user).to be_valid
end
end
context "emailを指定していないとき" do
let(:user) { build(:user, email: nil) }
it "エラーになる" do
user.valid?
expect(user.errors.messages[:email]).to include "can't be blank"
end
end
context "passwordを指定していないとき" do
let(:user) { build(:user, password: nil) }
it "エラーになる" do
user.valid?
expect(user.errors.messages[:password]).to include "can't be blank"
end
end
end
describe "validates uniqueness" do
context "保存されたメールアドレスが指定されたとき" do
let(:user1) { create(:user) }
let(:user2) { build(:user, email: user1.email) }
it "エラーになる" do
user2.valid?
expect(user2.errors.messages[:email]).to include "has already been taken"
end
end
end
end
devise_token_authでは、デフォルトでvalidates :email, :password, presence: true
とvalidates :email, uniqueness: true
が掛かっているのでこのようなテスト項目になりました。
仕様に応じてnameをpresence: trueにしてテストしてみたりしてください。
同じように書けばテスト通ります。
コントローラのテスト
テスト項目
ここではコントローラの処理のテストを行います。
routes.rbで指定されているルートに沿ってテストします。
今回コントローラー側でpassword_confirmをユーザー登録の条件に含めているのでそれもテストしていきます。
- ユーザー情報保存処理
- ユーザーが登録できること
- response.body["status"] = "success"
- response.body["data"]["id"] = 登録したユーザーid
- response.body["data"]["email"] = 登録したユーザーemail
- response.status = 200
- password_confirmationの値がpasswordと異なるときユーザー登録できない。
- password_confirmationを空白で登録しようとする
- response.body["status"] = "error"
- エラーメッセージに"Password confirmation doesn't match Password"が含まれる。
- response.status = 422
- ユーザーが登録できること
- ログイン処理
- email、passwordが正しいとき、ログインできること
- response.headers["uid"]が存在する
- response.headers["access-token"]が存在する
- response.headers["client"]が存在する
- response.status = 200
- emailが正しくない場合、ログインできないこと
- response.body["success"] = false
- response.body["errors"]が想定したエラー文と等しい
- response.headers["uid"]が空
- response.headers["access-token"]が空
- response.headers["client"]が空
- response.status = 401
- passwordが正しくない場合、ログインできないこと
- response.body["success"] = false
- response.body["errors"]が想定したエラー文と等しい
- response.headers["uid"]が空
- response.headers["access-token"]が空
- response.headers["client"]が空
- response.status = 401
- email、passwordが正しいとき、ログインできること
- ログアウト処理
- ログインしているとき、ログアウトできること
- response.body["success"] = true
- カレントユーザーのreload.tokensが空であること
- response.status = 200
- ログインしているとき、ログアウトできること
require "rails_helper"
RSpec.describe "Api::V1::Auth::Registrations", type: :request do
describe "POST /api/v1/auth" do
subject { post(api_v1_user_registration_path, params: params) }
context "値が正しく入力されているとき" do
let(:params) { attributes_for(:user) }
it "ユーザー登録できる" do
subject
res = JSON.parse(response.body)
expect(res["status"]).to eq("success")
expect(res["data"]["id"]).to eq(User.last.id)
expect(res["data"]["email"]).to eq(User.last.email)
expect(response).to have_http_status(200)
end
end
context "password_confirmationの値がpasswordと異なるとき" do
let(:params) { attributes_for(:user, password_confirmation: "") }
it "ユーザー登録できない" do
subject
res = JSON.parse(response.body)
expect(res["status"]).to eq("error")
expect(res["errors"]["full_messages"]).to include("Password confirmation doesn't match Password")
expect(response).to have_http_status(422)
end
end
end
describe "POST /api/v1/auth/sign_in" do
subject { post(api_v1_user_session_path, params: params) }
context "メールアドレス、パスワードが正しいとき" do
let(:current_user) { create(:user) }
let(:params) { { email: current_user.email, password: current_user.password } }
it "ログインできる" do
subject
expect(response.headers["uid"]).to be_present
expect(response.headers["access-token"]).to be_present
expect(response.headers["client"]).to be_present
expect(response).to have_http_status(200)
end
end
context "メールアドレスが正しくないとき" do
let(:current_user) { create(:user) }
let(:params) { { email: "test@example.com", password: current_user.password } }
it "ログインできない" do
subject
res = JSON.parse(response.body)
expect(res["success"]).to be_falsey
expect(res["errors"]).to include("Invalid login credentials. Please try again.")
expect(response.headers["uid"]).to be_blank
expect(response.headers["access-token"]).to be_blank
expect(response.headers["client"]).to be_blank
expect(response).to have_http_status(401)
end
end
context "パスワードが正しくないとき" do
let(:current_user) { create(:user) }
let(:params) { { email: current_user.email, password: "password" } }
it "ログインできない" do
subject
res = JSON.parse(response.body)
expect(res["success"]).to be_falsey
expect(res["errors"]).to include("Invalid login credentials. Please try again.")
expect(response.headers["uid"]).to be_blank
expect(response.headers["access-token"]).to be_blank
expect(response.headers["client"]).to be_blank
expect(response).to have_http_status(401)
end
end
end
describe "DELETE /api/v1/auth/sign_out" do
subject { delete(destroy_api_v1_user_session_path, headers: headers) }
context "ユーザーがログインしているとき" do
let(:current_user) { create(:user) }
let(:headers) { current_user.create_new_auth_token }
fit "ログアウトできる" do
subject
res = JSON.parse(response.body)
expect(res["success"]).to be_truthy
expect(current_user.reload.tokens).to be_blank
expect(response).to have_http_status(200)
end
end
end
end
こんな感じで書いてみました。
おわり
devise_token_auth実装〜Rspecテストを3記事に分けて書きました。
テスト項目がまだ未熟かもしれません。
気になった方は教えてください!