CodeBox CodeBox

【Rails】Rspecでテストコードを書いてみよう【モデル編】

Ruby / Rails
けい

RSpecって名前からして難しいので、敬遠してしまいがちですよね。でもルールを覚えるとめっちゃ簡単です!
今回はScaffoldでさくっと簡単なアプリを作成し、RSpecを体感してみましょう!

STEP1 Scaffoldでアプリの雛形をつくろう

Railsの「Scaffold」を使うと、簡単に必要最低限の機能を備えたアプリを作成できます。
まずはターミナル上で下記コマンドを順番に実行してください。

rails new rspec_practice
rails g scaffold article title:string content:string
rails db:migrate
rails s


ここまで実行すると下の画面が表示されます。


次に作成されたArticleモデルに対してバリデージョンを設定していきます。
バリデーションとは、例えば、記事のタイトルが未入力の場合は、エラーメッセージが出ると行ったような感じです。

では、article.rbを開き下記コードを追記してください。
サーバーを再起動して、次の章に進みましょう。

class Article < ApplicationRecord
	validates :title, presence: true
	validates :title, length: {minimum:2, maximum: 25}

	validates :content, presence: true
end


STEP2 RSpecの準備をしよう

次はRSpecの準備をしていきます。
RailsのGemfileを開き、下記を追加してください。

RSpecはリリースする前に正常に動くか確認するものなので、以下の場所に書くのが適切です。

group :development do
  gem 'rspec-rails'
end


追記できたら、ターミナルで「bundle install」を実行しましょう。
インストールが完了すると、「spec」フォルダと「.rspec」ファイルが作成されます。

次にテストコードを書くファイルを作成していきます。
ターミナルで下記コマンドを実行してください。

rails g rspec:install
//下記のファイルが作成される
//.rspec & spec/spec_helper.rb & spec/rails_helper.rb

rails g rspec:model article
//下記のファイルが作成される
//spec/models/post_spec.rb


STEP3 RSpecのテストコードを書いてみよう①

では実際にテストコードを書いていきます。
テストコードは以下のような構成になっていると理解しておいてください。

  1. 何を確認したいのか?
  2. 確認するためのデータを作成する
  3. 1で決めたことが実際に起こるか確認する



では、article_spec.rbファイルを開きます。まずは、コードを下記の状態にしてください。
*デフォルトでいらないコードが書かれている場合があるので、削除しておきます。

require 'rails_helper'

RSpec.describe Article, type: :model do

end


まずは記事のタイトルと内容が入力されている場合のテストコードを書いていきます。先程の構成に沿って考えていきましょう。

1.何を確認したいのか?
→タイトルと内容が入力されていれば、保存できること
2.確認するためのデータを作成する
→Article.newでダミーデータを作れば良さそう
3.1で決めたことが実際に起こるか確認する

では、再びarticle_spec.rbを開き、下記コードを貼り付けてください。

require 'rails_helper'

RSpec.describe Article, type: :model do
  context 'タイトルと内容が入力されている場合' do
    let!(:article) do
      Article.new({ title: 'RSpecテスト', content: 'RSpecテストの内容' })
    end
    it '記事を保存できる' do
      expect(article).to be_valid
    end
  end
end


ターミナルで下記コマンドを実行して結果を確認してみましょう。
赤字のエラーが表示されていなければ合格です。

bundle exec rspec spec/models/article_spec.rb


なんとなくテストがどんなものかイメージできたと思うので、先程のコードについて解説していきます。

テストに関する宣言は『describe』で書こう

テストコードの書き方には、様々なルールが設けられています。その中の一つが『describe』です。

describeは「今から〇〇を確認するテストコード書くよ〜」という宣言をする際に使います。
今回で言うと「Articleというモデルを確認しますよ〜」という意味で使われていますね。

RSpec.describe Article, type: :model do


ちなみにdescribeの内容は日本語でもOKです。

RSpec.describe "記事", type: :model do


テストで確認することは『it』を使って書こう

テストで確認したいことは、『it』を使うというルールがあります。
先程のコードでいうとこの部分ですね。

it '記事を保存できる' do

誰がみても何を確認しているのか分かるように書くのがベストです。

〇〇の場合は、『context』を使って書こう

次は『context』について解説していきます。先程のコードでも登場していましたね。contextには、テストの条件を書きます。

context 'タイトルと内容が入力されている場合' do


事前に変数を設定する場合は、『let!』を使おう

テストコードで使用する変数を定義する場合、『let!』を使いましょう。
テスト内で使用する変数は@articleというように『インスタンス変数』を使っても問題なくテストは通りますが、下記のような書き方は一般的ではありません。

RSpec.describe Article, type: :model do
  context 'タイトルと内容が入力されている場合' do
    before do
      @article = Article.new({ title: 'RSpecテスト', content: 'RSpecテストの内容' })
    end
    it '記事を保存できる' do
      expect(@article).to be_valid
    end
  end
end

テストコード内で何度も使用する変数はlet!を使うようにしましょう。

STEP4 RSpecのテストコードを書いてみよう

今度は別のテストコードを書いてみましょう。
では、次のコードをarticle_spec.rbに貼り付けてテストを実行してみましょう!

require 'rails_helper'

RSpec.describe Article, type: :model do
  context 'タイトルの文字が1文字の場合' do
    let!(:article_title_one_letter) do
      Article.create({ title: '1', content: 'RSpecテストの内容' })
    end
    it 'タイトルのエラーメッセージが出ること' do
      expect(article_title_one_letter.errors.messages[:title][0]).to eq('is too short (minimum is 2 characters)')
    end
  end
end


引っかかりそうなところは、let!で宣言している変数名とitの中身かなと思います。
変数名は何を表しているか直感的に分かるように書くのが基本なので、「タイトルが1文字の記事」という意味で、「articletitleone_letter」としました。

正しいエラーメッセージが表示されるか確認しよう

次にitの中身ですが、エラーメッセージが、「is too short (minimum is 2 characters)」となることを確認しています。
下記コードはタイトルに対するエラーメッセージを取り出すコードになっています。

article_title_one_letter.errors.messages[:title][0]

なぜこんなコードになるのか理解しづらい方のために、エラーメッセージがどのような構造になっているのか確認してみましょう!!

require 'rails_helper'

RSpec.describe Article, type: :model do
  context 'タイトルの文字が1文字の場合' do
    let!(:article_title_one_letter) do
      Article.create({ title: '1', content: 'RSpecテストの内容' })
    end
    it 'タイトルのエラーメッセージが出ること' do
      #下記を追記
      puts article_title_one_letter.errors.messages
      expect(article_title_one_letter.errors.messages[:title][0]).to eq('is too short (minimum is 2 characters)')
    end
  end
end


テストを実行すると下記のような結果がえられると思います。
これがエラーメッセージの内容です。

{:title=>["is too short (minimum is 2 characters)"]}


実はエラーメッセージはハッシュになっているのです!
つまり先程のarticletitleone_letter.errors.messages[:title][0]を文字で説明するとこんな感じですね。

以上でRSpecの解説は以上です。

ABOUT ME

けい
ベンチャーのフロントエンジニア。 主にVueとTypescriptを使っています。ライターのための文字数カウントアプリ:https://easy-count.vercel.app/