LoginSignup
1
0

More than 3 years have passed since last update.

RSpecはここから始めよう

Last updated at Posted at 2020-02-26

Everyday Rails - RSpecによるRailsテスト入門を読みました。
まずはここから始めようと思ったことをまとめます。

導入方法については以下の記事を参照
RSpecを導入する

用語

spec:テストファイル
example:spec内に書かれているテスト1つ1つ

specの種類

モデルスペック、コントローラースペック、フィーチャースペック、システムスペック、レスポンススペックの5種類があります。特に重要なのは以下の3つです。

モデルスペック:バリデーションや、メソッドの単体テスト。

システムスペック:統合テスト。ユーザーの動作を再現する。手動テストを自動でやる感じ。
昔はフィーチャースペックが使われていたけど、今はこっちが推奨されてるみたいです。
実行に時間がかかります。

レスポンススペック:主に外部APIとの通信をするテストで使われます。

基本文法

まずit '<テスト名>' do ~ endのブロックの中にデータのセットアップや検証したい項目を書きます。

it 'can have many notes' do
  #検証したい内容が入る
end

次にexpect(<検証したい項目>).to <どうなっていて欲しいか>を書きます。英語の文法と同じ語順なのでとても読みやすくて気に入っています。

it 'can have many notes' do
  project = ... #データのセットアップなど
  expect(project).to be_valid
end

以下のコマンドでテストを実行します。

$ bin/rspec
.
.
Finished in 3.12 seconds (files took 0.93752 seconds to load)
1 examples, 0 failures

テストデータの生成

各テスト内でUser.newなどで生成しても全然オッケーなのですが、めんどくさいので、FactoryBotというgemを使います。

$ bin/rails g factory_bot:model user
spec/factories/users.rb
FactoryBot.define do
  factory :user do
    name { 'Sample Tarou' }
    email { 'test@example.com' }
    password { 'mypassword1234' }
  end
end

あとはテスト内にFactoryBot.create(:user)と書くだけで、上記のユーザーのインスタンスを生成することができます。

spec/models/user.rb
it 'is valid with a name, email, and password' do
  user = FactoryBot.create(:user)
  expect(user).to be_valid
end

モデルスペック

$ bin/rails g rspec:model user
spec/models/user_spec.rb
require 'rails_helper'

RSpec.describe User, type: :model do
  #emailのバリデーションのテスト
  it { is_expected.to validate_presence_of :email }

  #フルネームを返すnameメソッドのテスト
  it "returns a user's full name as a string" do
    user = FactoryBot.build(:user, first_name: 'John', last_name: 'Doe')
    expect(user.name).to eq 'John Doe'
  end
end

システムスペック

$ bin/rails g rspec:system project
spec/system/projects_spec.rb
require 'rails_helper'

RSpec.feature 'Projects', type: :system do
  it 'edits a project' do
    sign_in_as user
    visit root_path
    click_link 'Test Project 1'
    click_link 'Edit'
    fill_in_project_info('test_updated', 'hogefuga')
    click_button 'Update Project'
    expect(page).to have_content 'test_updated'
  end

  it 'creates a new project' do
    sign_in_as user
    expect do
      click_link 'New Project'
      fill_in_project_info('Test Project', 'Trying out Capybara')
      click_button 'Create Project'

      aggregate_failures do
        expect(page).to have_content 'Project was successfully created'
        expect(page).to have_content 'Test Project'
        expect(page).to have_content "Owner: #{user.name}"
      end
    end.to change(user.projects, :count).by(1)
  end
end

リクエストスペック

bin/rails g rspec:request home
spec/requests/homes_spec.rb
require 'rails_helper'

RSpec.describe "Homes", type: :request do
  it 'responds successfully' do
    get root_path
    expect(response).to be_success
    expect(response).to have_http_status '200'
  end
end

共通のテストデータ

letを利用することで、1つのファイル内で共通で使うテストデータを作成することができます。

spec/models/user.rb
let(:user) { FactoryBot.create(:user) }

it 'is valid with a name, email, and password' do
  expect(user).to be_valid
end

it 'is Sample Tarou' do
  expect(user).to eq 'Sample Tarou'
end

上の例ではletを使いuserという変数の中にファクトリに定義したユーザーのインスタンスを格納しました。

exampleをグループ分けする

describecontextを使って、exampleをグループ分けすることで、可読性をあげることができます。

describe 'search message for a term' do
  context 'when a match is found' do
    it 'returns notes that match the search term' do
      .
      .
    end
  end

  context 'when no match is found' do
    it 'returns an empty collenction when no result are found' do
      .
      .
    end

    it 'returns an empty collenction when serach conditions are invalid' do
      .
      .
    end
  end
end

capybara

システムスペックを書く上でcapybaraというgemが必要です。
インストールすると、capybaraのDSL(独自の言語)が使えるようになります。
以下のvisitclick_linkfill_inclick_buttonなどがDSLです。非常に直感的で気に入っています。

specs/systems/projects_spec.rb
it 'signs in' do
  visit root_path
  click_link 'Sign In'
  fill_in 'Email', with: user.email
  fill_in 'Password', with: user.password
  click_button 'Log in'
  expect(page).to have_content 'ようこそ Sample Tarou 様'
end

shoulda-matchers

shoulda-matchersというgemを使うと、macher(be_validとか)を拡張することができ、特にモデルスペックのバリデーションのチェックで力を発揮します。

it 'is invalid without a first name' do
  user = FactoryBot.build(:user, first_name: nil)
  user.valid?
  expect(user.errors[:first_name]).to include("can't be blank")
end

このバリデーションチェックのテストが

it { is_expected.to validate_presence_of :first_name }

このように1行で検証できるようになります。

デフォルトで使えるマッチャーについては以下の記事を参照
使えるRSpec入門・その2「使用頻度の高いマッチャを使いこなす」

メソッドを切り出す

複数箇所で共通する処理は、メソッドとして切り出すことができる。
ファイルの一番下に書くことが多い。

def go_to_project(name)
  visit root_path
  click_link name
end

複数のファイルで共通する処理はspecs/supportディレクトリにファイルを作る。

spec/support/login_support.rb
module LoginSupport
  def sign_in_as(user)
    visit root_path
    click_link "Sign in"
    fill_in "Email", with: user.email
    fill_in "Password", with: user.password
    click_button "Log in"
  end
end
spec/rails_helper.rb
#以下のように記述することで、各ファイルでincludeする必要がなくなる
RSpec.configure do |config|
  config.include LoginSupport
end

明示的に読み込みたい場合には、各ファイル内でinclude LoginSupportのように記述する。

終わりに

他にもたくさんTIPS的なものがありますが、全部いきなり全部意識するのは無理なので、まずはこの記事にまとめたテクニックでどんどんテストを書いていきます。

参考

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