LoginSignup
1
3

More than 3 years have passed since last update.

【Ruby on Rails】モデルの単体テストコードについてまとめ(RSpec)

Last updated at Posted at 2021-03-04

初学者です。
テストコードがなぜか大好きです。

今回はモデルの単体テストコードについてまとめます。
私はRSpecを利用しています。

モデルのテストコードを書く方針は
インスタンスを生成し、そのインスタンスがモデルに規定したどおりの挙動になるか(バリデーションが正しく働くか等)を確かめる
ことです。

前提条件

  • pry-railsを導入済みである
  • FactoryBotを導入済みである

上記については以下の記事にまとめています。

【Ruby on Rails】デバッグツール(pry-rails)
【Ruby on Rails】FactoryBotとFakerについてまとめ

RSpec

RSpecは、Railsのテストコードを書くために用いられるGemです。
RSpec公式Github

テストコードの種類

  • 単体テストコード

    モデルやコントローラーなど機能ごとに問題がないか確認します。
    例えばバリデーションがきちんと動作しているかなどです。

  • 結合テストコード

    ユーザーがブラウザで操作する一連の流れを再現して問題がないか確かめます。
    例えば、ユーザー登録で「名前とメールアドレスとパスワードを入力するとトップページに遷移して表示がユーザーの名前に変わっている」などの一連の動作を確認します。

  • 正常系

    ユーザーが開発者の意図する操作を行った時の挙動を確認するテストコードです。
    例えば、ユーザー登録で問題なく全てのデータが入力された場合などです。

  • 異常系

    ユーザーが開発者の意図しない操作を行った時の挙動を確認するテストコードです。
    例えば、ユーザー登録で正しい値が入っていないと登録できないかどうかなどです。

RSpec導入

下記のようにGemfilegroup :development, :test dogem 'rspec-rails', '~> 4.0.0'と記述します。

Gemfile
group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]

# 以下を追加
  gem 'rspec-rails', '~> 4.0.0'
end

ターミナルで下記のコマンドを実行しGemを導入します。

ターミナル
bundle install

ターミナルで下記のコマンドを実行しアプリケーション内でRSpecを使用するための設定を行います。実行すると関連するファイルが生成されます。

ターミナル
rails g rspec:install

生成された.rspecに下記のように記述します。
テストコードの結果をターミナルで可視化するために必要な記述です。

.rspec
--require spec_helper

# 以下を追加
--format documentation

ターミナルで下記のコマンドを実行しテストコードを記述するファイルを生成します。

ターミナル
rails g rspec:model モデル名

# 以下はuserモデルのファイル生成の例
rails g rspec:model user

テストコードを記述するファイルは手動で生成してもいいのですが、require 'rails_helper'の記述がないと読み込めないファイルがあり、きちんとテストできないのでコマンドで生成した方がいいみたいです。

もし、このコマンドで生成した際に既にFactoryBotが導入済みであればFactoryBotのファイルも一緒に生成してくれますし楽だと思います。

単体テストコードの準備

本題です。
まだ業務経験もないペーペーなのであしからず。

ユーザー登録についての単体テストコードを例にします。

最初に何を検証すべきなのかを洗い出していきます。

spec/models/user_spec.rb
require 'rails_helper'

RSpec.describe User, type: :model do

# FactoryBotでデータをbuild
  before do
    @user = FactoryBot.build(:user)
  end

  describe 'ユーザー新規登録' do

# 正常系
    context '新規登録できる時' do
      it '全ての項目が存在すれば登録できる' do
      end
      it 'nameが6文字以下であれば登録できる' do
      end
      it 'passwordとpassword_confirmationが6文字以上であれば登録できる' do
      end
    end

# 異常系
    context '新規登録できない時' do
      it 'nameが空だと登録できない' do
      end
      it 'emailが空だと登録できない' do
      end
      it 'passwordが空だと登録できない' do
      end
      it 'passwordが存在してもpassword_confirmationが空だと登録できない' do
      end
      it 'nameが7文字以上では登録できない' do
      end
      it '重複したemailが存在する場合登録できない' do
      end
      it 'passwordが5文字以下では登録できない' do
      end
    end
  end
end

解説していきます。

まず以下のようにbefore doでFactoryBotのデータをbuildします。
インスタンス変数にする必要があるので@userになります。

before do
    @user = FactoryBot.build(:user)
end

次に以下のようにdescribeどの機能についてのテストを行うかを記述します。
グループ分けのようなものです。

describe 'ユーザー新規登録' do

end

次に以下のようにcontextでさらに分けていきます。
contextではどんな状況を確認したいのかで分けるので、私は正常系と異常系に分けて考えます。

# 正常系
context '新規登録できる時' do

end

# 異常系
context '新規登録できない時' do

end

次に以下のようにitでさらに細かい機能に分けます。
itに書いた確認したい状況をテストしていきます。

it '全ての項目が存在すれば登録できる' do

end

正常系

正常系を書いていきます。

spec/models/user_spec.rb
context '新規登録できる時' do

  it '全ての項目が存在すれば登録できる' do
    expect(@user).to be_valid
  end

  it 'nameが6文字以下であれば登録できる' do
    @user.name = 'abcde'
    expect(@user).to be_valid
  end

  it 'passwordとpassword_confirmationが6文字以上であれば登録できる' do
    @user.password = '123456'
    @user.password_confirmation = '123456'
    expect(@user).to be_valid
  end
end

解説します。

まず「全ての項目が存在すれば登録できる」についてです。
expect(@user)@userbe_validで正しいかどうかを判断しています。

expect(@user).to be_valid

次は「nameが6文字以下であれば登録できる」についてです。
@user.nameabcde(つまり6文字以下の文字列)を代入して、そのデータが入った@userbe_validで正しいかどうかを判断しています。

@user.name = 'abcde'
@expect(@user).to be_valid

次に「passwordとpassword_confirmationが6文字以上であれば登録できる」についてです。
nameと同じように@user.password123456を代入し、そのデータが入った@userbe_validで正しいかどうかを判断しています。

@user.password = '123456'
@user.password_confirmation = '123456'
expect(@user).to be_valid

これで成功するかどうかターミナルに以下を入力します。

ターミナル
bundle exec rspec spec/models/user_spec.rb

成功したら緑色の文字で結果が出力されます。

異常系

1つを例に解説します。
「nameが空だと登録できない」についてを例にします。

it 'nameが空だと登録できない' do

  # 下記を追加
  @user.name = ''
  @user.valid?
  binding.pry

end

まずFactoryBotでデータを入れてある@userのnameに「''」のように空を代入します。
次にvalid?で正しいか?(trueかfalseを返す)を確認しています。

そしてbinding.pryで処理を止める記述をしました。
この状態でターミナルに以下を入力すると処理が止まります。

ターミナル
bundle exec rspec spec/models/user_spec.rb

処理が止まりコンソールに入力できるようになるのでuser.errors.full_messagesと入力するとメッセージが出てきます。
そのメッセージを踏まえてテストコードを変更していきます。

it 'nameが空だと登録できない' do

  @user.name = ''
  @user.valid?

# 以下を変更
  expect(@user.errors.full_messages).to include("name can't be blank")

end

上記の記述はexpectの引数にincludeの引数が含まれるという意味です。
先ほどuser.errors.full_messagesで出てきたメッセージをincludeの引数に与えることで一致する(含まれる)ということになります。

こんな感じで記述していきます。

以上です。

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3