Help us understand the problem. What is going on with this article?

【RSpec】【実践的】使えるテクニック・知識。

はじめに

自分はRSpecについての理解が全然ない状態で勉強してある程度は使えるようになりました!
初心者なりに実践的な使い方やコツをまとめてみたのでよかったらご覧ください。

テクニック・知識集

TDDとは

テスト駆動開発(Test-Driven Development)の略で、テストファーストなプログラムの開発手法のこと。
少しわかりやすく言うと、プログラムの実装前にテストコードを書き、そのテストコードに適合するように実装とリファクタリングを進めていく方法です。

is_expected

exampleを一行で書くために使う書き方です。

it { is_expected.to eq(2) }

use_before_action()

コントローラーで設定したbefore_actionをテスト環境で実行する。

it { is_expected.to use_before_action(:set_article) }

respond_with()

レスポンスの種類、状態を返す。

is_expected.to respond_with(:redirect)

is_expected.to respond_with 200

is_expected.to respond_with(:success)

redirect_to()

引数に与えたパスにリダイレクトする。

is_expected.to redirect_to(new_user_session_path)

set_flash[]

与えた値のフラッシュメッセージが表示されているか確認する。

is_expected.to set_flash[:notice]

render_with_layout()

描画されているのが引数の指定したものかを確認する。

is_expected.to render_with_layout(:application)

render_template()

引数に指定したアクションのビューが表示されているか確認。

is_expected.to render_template(:index)

assigns

コントローラのインスタンス変数をテストするメソッド。

# @articlesをテストしている
expect(assigns[:articles].to_sql).to eq Article.order(id: :desc).limit(25).offset(0).to_sql

attributes_for

プロジェクトファクトリからテスト用の属性値をハッシュとして作成します。


# 属性のハッシュを生成
alice = attributes_for(:alice)
=> {:name=>"Alice", :admin=>true}

テスト時のHTTPリクエストの仕方

get :edit, params: { id: article.id }

post :create, params: { article: article_params }

patch :update, params: { id: article.id, article: edit_article_params }

shared_examples / it_behaves_like

よく使う処理をshared_examplesでまとめて、it_behaves_likeで使うもの。




shared_examples '未ログイン時のテスト' do
    it 'result' do
      # response
      is_expected.to respond_with(:redirect)
      is_expected.to redirect_to(new_user_session_path)

      # flash
      is_expected.to_not set_flash[:notice]
    end
  end



    context '未ログイン時' do
      before { get :new }

      it_behaves_like '未ログイン時のテスト'
    end

faxtorybotのアソシエーション方法

FactoryBot.define do
  factory :comment do
    association :article
    comment  { 'comment' }
  end
end

validate_presence_of

カラムの存在性をテストするもの。

is_expected.to validate_presence_of(:title)

validate_length_of / is_at_most

カラムの長さを調べる。is_at_mostで最大数を調べる。

is_expected.to validate_length_of(:title).is_at_most(255)

validate_uniqueness_of

カラムが一意性があるか確認する。

is_expected.to validate_presence_of(:username)

ルーティングのテストの書き方

it { is_expected.to route(:get, '/').to(controller: 'articles', action: 'index') }

attr_accessor

クラスやモジュールにインスタンス変数を読み書きするためのアクセサメソッドを定義する。
引数には、インスタンス変数名をシンボルか文字列で指定し複数指定できる。
定義されたメソッドは、シンボルの名前の先頭に「@」を付加したインスタンス変数の値を取り出す。
簡単に言うと、外部からインスタンス変数にアクセスが可能になる。

shared_context / include_context

context を再利用するためのもの。




  shared_context '12歳の場合' do
    let(:age) { 12 }
  end



    context '12歳以下の場合' do
      include_context '12歳の場合'
      it { is_expected.to eq 'ぼくはU-12だよ。' }
    end

let!

通常のletだと、遅延評価されるが「!」をつけるとexampleの前に実行してくれるようになる。

pending

なぜかどうしてもテストがパスしないといったテストを、一旦保留にしたいときに使います。

RSpec.describe '謎クラス' do
  it '謎テスト' do
    expect(1 + 2).to eq 3

    pending 'この先はなぜかテストが失敗するので保留'
    # パスしないエクスペクテーション(実行される)
    expect(foo).to eq bar
  end
end

skip

指定した場所でテストの実行を止めたい場合に使います。

RSpec.describe '実行したくないクラス' do
  it '実行したくないテスト' do
    expect(1 + 2).to eq 3

    skip 'とりあえずここで実行を止める'
    # ここから先は実行されない
    expect(foo).to eq bar
  end
end

xit

example全体を手っ取り早くskipさせたいときは it を xit に変更するとそのexampleは実行されなくなります。(pending 扱い)

RSpec.describe '何らかの理由で実行したくないクラス' do
  xit '実行したくないテスト' do
    expect(1 + 2).to eq 3

    expect(foo).to eq bar
  end
end

xdescribe / xcontext

describe や context にも x を付けることでスキップできる。

# グループ全体をskipする
xdescribe '四則演算' do
  it '1 + 1 は 2 になること' do
    expect(1 + 1).to eq 2
  end
  it '10 - 1 は 9 になること' do
    expect(10 - 1).to eq 9
  end
end

# グループ全体をskipする
xcontext '管理者の場合' do
  it '社員情報を編集できる' do
    # ...
  end
  it '社員情報を削除できる' do
    # ...
  end
end

よく使うマッチャ

マッチャ(matcher)は「期待値と実際の値を比較して、一致した(もしくは一致しなかった)という結果を返すオブジェクト」のことです。
以降は良く使うマッチャをいくつか紹介します。

eq

期待値と実際の値が「等しい」かどうかを検証する

expect(1 + 2).to eq 3

be

等号・不等号と組み合わせて、値の大小を検証する

expect(1 + 2).to be >= 3

be_xxx (predicateマッチャ)

戻り値が true / false になるメソッドを検証できる

expect([]).to be_empty?

expect(article).to be_valid?

be_truthy / be_falsey

「trueっぽい値」または「falseっぽい値」かどうかを検証する。

# 必須項目が入力されていないので保存できない(結果はfalse)
user = User.new
expect(user.save).to be_falsey 

# 必須項目が入力されているので保存できる(結果はtrue)
user.name = 'Tanaka'
user.email = 'tanaka@example.com'
expect(user.save).to be_truthy

change + from / to / by

X すると Y が A から B に変わることを期待することを検証します。

x = [1, 2, 3, 4, 5]
expect{ x.pop }.to change{ x.size }.from(5).to(4)

include

~が含まれていることを検証する。

x = [1, 2, 3]
expect(x).to include 1

raise_error

「エラーが起きること」を検証する。

it 'nilを追加するとエラーが発生すること' do
  cart = Cart.new
  expect{ cart.add nil }.to raise_error 'Item is nil.'
end

be_within + of

数値 X がプラスマイナス Y の範囲内に収まっていることを検証する。

it '当選確率が約25%になっていること' do
  results = Lottery.generate_results(10000)
  win_count = results.count(&:win?)
  probability = win_count.to_f / 10000 * 100

  expect(probability).to be_within(1.0).of(25.0)
end

RSpecマナーの教え

其の1 : describe の引数にはテストの対象を書く

其の2 : context の引数にはテストが実行される際に前提になる条件や状態を書く

其の3 : describe 外にテストデータを置かない

其の4 : letを上書きしない

其の5 : DRYよりも読みやすさ重視!

終わりに

ここまでRSpecに役立つ知識やテクニックを詰め込んできましたが、実際に作業しているとよくわからないことばかり出てきますが、分からないことは誰かに調べたり、誰かに聞いたりしてとにかく経験値を積み上げていくのがテストマスターへの近道では無いかと思います!
自分も頑張ろう。。

ren0826jam
プログラミング歴数ヶ月の初心者ですが、よろしくお願いします。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした