LoginSignup
0
0

More than 3 years have passed since last update.

RSpecまとめ

Posted at

RSpecについて、知識の定着がまだまだなのでまとめがてら復習しておきたいと思います

RSpecとは

ソフトウェアテストの一種でプログラムが想定通り動くかテストする。テストしたい項目の単位を「テストケース」という。

ログイン機能を例とすると、

 ログインできる=正しいパスワード
 ログインできない=正しくないパスワード
となる。

RSpecをインストールする

名前 概要
rspec-rails Rails向けのRSpec テストのフレームワーク
factory_bot_rails 自動テストで使うテストデータの用意が簡単になる
Gemfile

source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

    :
  (省略)
    :

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', '~> 3.8'
  gem 'factory_bot_rails', '~> 5.0'


end

group :development do

    :
  (省略)
    :

end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]


↓

bash
$ bin/bundle install

テストの種類

手動テスト

人がテストケースを読み、確認してテストすることを「手動テスト」という。

これといった正解のない、レイアウトやアニメーションの確認をするときに有効。ただし、工数が多くなりやすい、テストの操作を間違えやすいというデメリットもある。

自動テスト

テストケースをプログラムに書いて実行する。簡単、高速、確実だが、既存機能の仕様変更の際、テストコードの修正も必要になる。

テストレベルとは

テストは開発工程ごとで範囲や細かさが違います。WEBアプリケーションの開発では主に「単体テスト」「結合テスト」「システムテスト」がある。

単体テスト

その名の通り、小さな範囲をテストする。

モデルの場合、データを正しく参照できるか、登録できているか
メソッドの場合、与えた引数に対して正しい戻り値が返ってくるか
をテスト。

※例
require 'rails_helper'

RSpec.describe FoodEnquete, type: :model do
  describe '正常系の機能' do
    context '回答する' do
      it '正しく登録できること 料理:やきそば food_id: 2, 
                            満足度:良い score: 3, 
                            希望するプレゼント:ビール飲み放題 present_id: 1)' do

        enquete = FoodEnquete.new(
          name: '田中 太郎',
          mail: 'taro.tanaka@example.com',
          age: 25,
          food_id: 2,
          score: 3,
          request: 'おいしかったです。',
          present_id: 1
        )

        expect(enquete).to be_valid

        enquete.save

        answered_enquete = FoodEnquete.find(1);

        expect(answered_enquete.name).to eq('田中 太郎')
        expect(answered_enquete.mail).to eq('taro.tanaka@example.com')
        expect(answered_enquete.age).to eq(25)
        expect(answered_enquete.food_id).to eq(2)
        expect(answered_enquete.score).to eq(3)
        expect(answered_enquete.request).to eq('おいしかったです。')
        expect(answered_enquete.present_id).to eq(1)

      end
    end
  end
end

キーワード 命名 意味
describe 正常系の機能 大分類 何についてテストをするか
context 回答する 中分類 分類が少ないときは省略できる
it 正しく登録できること... 個々のテストケースを表し、期待する振舞いを記述

RSpecの記法

※バリデーションが通ること(バリデーションエラーが無いこと)

expect(enquete).to be_valid


※answered_enquete.nameが田中 太郎であること

expect(answered_enquete.name).to eq('田中 太郎')
項目 意味
expect テストしたいものを指定 テストデータenqueteを指定
to 「であること」を意味する
be_valid テストデータenqueteのバリデーションが通ること

この中でbe_validは検証の種類である「マッチャー」に分類される。マッチャーにはeqやlncludeなどがある。

実行

$ bundle exec rspec 〇〇(ファイル名)

F

Failures:

  1) FoodEnquete 正常系の機能 回答する 正しく登録できること 料理:やきそば food_id: 2, 
                            満足度:良い score: 3, 
                            希望するプレゼント:ビール飲み放題 present_id: 1)
    Failure/Error: expect(answered_enquete.name).to eq('中田 太郎')

      expected: "中田 太郎"
           got: "田中 太郎"

      (compared using ==)
    # ./spec/models/food_enquete_spec.rb:23:in `block (4 levels) in <top (required)>'

Finished in 0.02235 seconds (files took 0.83042 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/models/food_enquete_spec.rb:6 # FoodEnquete 正常系の機能 回答する 正しく登録できること 料理:やきそば food_id: 2, 
                            満足度:良い score: 3, 
                            希望するプレゼント:ビール飲み放題 present_id: 1)

FactoryBot

テストデータを呼び出せるようにする


       enquete_tanaka = FoodEnquete.new(
         name: '田中 太郎',
         mail: 'taro.tanaka@example.com',
         age: 25,
         food_id: 2,
         score: 3,
         request: 'おいしかったです。',
         present_id: 1
       )
       enquete_tanaka.save

↓テストデータを置き換える↓

FactoryBot.create(:food_enquete)

FactoryBot用のファイルを作り、:food_enquete(Factory名)からテストデータを呼び出せる


FactoryBot.define do
  factory :food_enquete do
    name { '田中 太郎' }
    mail { 'taro.tanaka@example.com' }
    age { 25 }
    food_id { 2 }
    score { 3 }
    request { 'おいしかったです。' }
    present_id { 1 }
  end
end

共通化

before 前処理

describe 'アンケート回答時の条件' do
  context 'メールアドレスを確認すること' do
    it '同じメールアドレスで再び回答できないこと' do

      # FactoryBot.create(:food_enquete_tanaka)

      re_enquete_tanaka = FactoryBot.build(:food_enquete_tanaka, food_id: 0, score: 1, present_id: 0, request: "スープがぬるかった")
      expect(re_enquete_tanaka).not_to be_valid
      expect(re_enquete_tanaka.errors[:mail]).to include(I18n.t('errors.messages.taken'))
      expect(re_enquete_tanaka.save).to be_falsey
      expect(FoodEnquete.all.size).to eq 1
    end

    it '異なるメールアドレスで回答できること' do

      # FactoryBot.create(:food_enquete_tanaka)

      enquete_yamada = FactoryBot.build(:food_enquete_yamada)

      expect(enquete_yamada).to be_valid
      enquete_yamada.save
      expect(FoodEnquete.all.size).to eq 2
    end
  end

.
.

#同じテストデータを呼び出す処理
FactoryBot.create(:food_enquete_tanaka)

↓

# 前処理を共通化してテストデータを作成。  
before do
  FactoryBot.create(:food_enquete_tanaka)
end

.
.

describe 'アンケート回答時の条件' do
  context 'メールアドレスを確認すること' do


    # 前処理を共通化してテストデータを作成。  
    before do
      FactoryBot.create(:food_enquete_tanaka)
    end


    it '同じメールアドレスで再び回答できないこと' do

    #まずはbeforeを実行してくれる

      re_enquete_tanaka = FactoryBot.build(:food_enquete_tanaka, food_id: 0, score: 1, present_id: 0, request: "スープがぬるかった")
      expect(re_enquete_tanaka).not_to be_valid
      expect(re_enquete_tanaka.errors[:mail]).to include(I18n.t('errors.messages.taken'))
      expect(re_enquete_tanaka.save).to be_falsey
      expect(FoodEnquete.all.size).to eq 1
    end

    it '異なるメールアドレスで回答できること' do

   #まずはbeforeを実行してくれる

      enquete_yamada = FactoryBot.build(:food_enquete_yamada)

      expect(enquete_yamada).to be_valid
      enquete_yamada.save
      expect(FoodEnquete.all.size).to eq 2
    end
  end

他にも、このような形で
インスタンス

new_enquete = FoodEnquete.new
↓
let(:new_enquete) { FoodEnquete.new }

共通メソッド

#共通化したいメソッド
shared_examples '満足度の表示' do
  let(:object_name) { described_class.to_s.underscore.to_sym }
  let(:model) { FactoryBot.build(object_name) }

  it '満足度が「悪い」になること' do
    model.score = 1
    expect(model.view_score).to eq I18n.t('common.score.bad')
  end

  it '満足度が「普通」になること' do
    model.score = 2
    expect(model.view_score).to eq I18n.t('common.score.normal')
  end
.
.  
.
  end

↓

  describe '共通メソッド' do
    it_behaves_like '満足度の表示'
  end

共通バリデーション

shared_examples '入力項目の有無' do
  let(:object_name) { described_class.to_s.underscore.to_sym }
  let(:model) { FactoryBot.build(object_name) }

  context '必須入力であること' do
    it 'お名前が必須であること' do
      expect(model).not_to be_valid
      expect(model.errors[:name]).to include(I18n.t('errors.messages.blank'))
    end

.
.
end
.
.
.
end

↓

  describe '共通バリデーション' do
    it_behaves_like '入力項目の有無'
    it_behaves_like 'メールアドレスの形式'    
  end


など、共通化できるものが数多くある

結合テスト

必要なGem

名前 概要
capybara 結合テスト(E2E)のフレームワーク。自動操作を支援する。
selenium-webdriver capybaraを通してWEBブラフザを自動で操作。
webdrivers Google Chromeを操作するドライバ
#Gemfile

.
.
# 追加する
group :test do
  gem 'capybara', '~> 3.28'
  gem 'selenium-webdriver', '~> 3.142'
  gem 'webdrivers', '~> 4.1'
end

↓
bash
$ bin/bundle install

spec/spec_helper.rbのコードを修正

#Capybaraを参照
require 'capybara/rspec'

#ブラウザにChromeを指定
  config.before(:each, type: :system) do
    driven_by :selenium, using: :chrome, screen_size: [1280, 960]
  end

.
.
結合テスト用のファイルを作成

require 'rails_helper'

RSpec.describe "FoodEnquetes", type: :system do
  describe '正常' do
    context "アンケートに回答する" do
      it "回答できること" do

        enquete = FactoryBot.create(:food_enquete_tanaka)
        visit "/food_enquetes/new"
        fill_in 'お名前', with: enquete.name
        fill_in 'メールアドレス', with: enquete.mail
        fill_in '年齢', with: enquete.age
        select enquete.food_name, from: 'お召し上がりになった料理'
        choose "food_enquete_score_#{enquete.score}"
        fill_in 'ご意見・ご要望', with: enquete.request
        select enquete.present_name, from: 'ご希望のプレゼント'

        sleep 2
        click_button '登録する'

        expect(page).to have_content 'ご回答ありがとうございました'
        expect(page).to have_content 'お名前: 田中 太郎'
        expect(page).to have_content 'メールアドレス: taro.tanaka@example.com'
        expect(page).to have_content '年齢: 25'
        expect(page).to have_content 'お召し上がりになった料理: やきそば'
        expect(page).to have_content '満足度: 良い'
        expect(page).to have_content 'ご意見・ご要望: おいしかったです。'
        expect(page).to have_content 'ご希望のプレゼント: 【10名に当たる】ビール飲み放題'


      end
    end
  end
end

↓
bash
$ bundle exec rspec 〇〇ファイル名

すると、自動的にChromeが起動してアンケートの回答をしてくれる。

0
0
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
0
0