1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【RSpec】基本的な書き方

Last updated at Posted at 2021-05-12

#はじめに
この記事は、使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」を参考(引用)してます。

#describe / it / expect の役割
RSpecでよく使うdescribe, it, expectについて。
##describe テストのグループ化
・ describeはテストのグループ化を宣言する。
・ describeの中では複数のexample(it end ... do)を記述できる。

##it テストをexampleにまとめる
・ itはテストをexampleという単位にまとめる役割をする。
it do ... endの中のエクスペクテーション(期待値と実際の値の比較)が全てパスすればそのexampleはパスしたことになる。
it do ... endのなかには一つのエクスペクテーション(expect)を描く。(原則なので破っても良い)

##expect エクスペクテーション
itの部分で述べたエクスペクテーションがexpectにあたり、
expect(X).to eq Yのような形で描く。

#使えると便利なcontext / before
###context
contextは条件でグループ化するときに使う。

RSpec.describe User do
  describe '#greet' do
    context '12歳以下の場合' do
      it 'ひらがなで答えること' do
        user = User.new(name: 'たろう', age: 12)
        expect(user.greet).to eq 'ぼくはたろうだよ。'
      end
    end
    context '13歳以上の場合' do
      it '漢字で答えること' do
        user = User.new(name: 'たろう', age: 13)
        expect(user.greet).to eq '僕はたろうです。'
      end
    end
  end
end

###before
・ beforeは共通の前準備をする時に使える。
before do ... endに記述したものは、
 example(it do ... end)の実行前に呼ばれる。
・ beforeはテスト実行前の共通処理やデータのセットアップ等を行うことが多い。

RSpec.describe User do
  describe '#greet' do
    before do
      @params = { name: 'たろう' }
    end
    context '12歳以下の場合' do
      it 'ひらがなで答えること' do
        user = User.new(@params.merge(age: 12))
        expect(user.greet).to eq 'ぼくはたろうだよ。'
      end
    end
    context '13歳以上の場合' do
      it '漢字で答えること' do
        user = User.new(@params.merge(age: 13))
        expect(user.greet).to eq '僕はたろうです。'
      end
    end
  end
end

beforeではインスタンス変数を使用している。
これはbeforeitでは変数のスコープが異なるため。

####ネストしたdescribe, contextの中でのbefore
beforeはdescribecontextごとに用意できる。
呼ばれる順番は、親、子の順。

RSpec.describe User do
  describe '#greet' do
    before do
      @params = { name: 'たろう' }
    end
    context '12歳以下の場合' do
      before do
        @params.merge!(age: 12)
      end
      it 'ひらがなで答えること' do
        user = User.new(@params)
        expect(user.greet).to eq 'ぼくはたろうだよ。'
      end
    end
    context '13歳以上の場合' do
      before do
        @params.merge!(age: 13)
      end
      it '漢字で答えること' do
        user = User.new(@params)
        expect(user.greet).to eq '僕はたろうです。'
      end
    end
  end
end

#letの役割
###インスタンス変数の代わり
これまではbeforeブロックに@paramsという形でインスタンス変数を利用してきました。これをletを使って次のように書き換えられる。

#これを
  before do
    @params = { name: "たろう" }
  end
#このように
  let(:params) { { name: "たろう" } }

###ローカル変数の代わりにも
インスタンス変数だけでなく、ローカル変数もletでかける。

#これを
  user = User.new(params)
#このように
  let(:user) = User.new(params)

###letのメリット
beforeexpample(it do ... end)の前に呼ばれるのに対し、letは遅延評価される。letは必要になるまで呼ばれない。

RSpec.describe User do
  describe '#greet' do
    let(:user) { User.new(params) }
    let(:params) { { name: 'たろう', age: age } }
    context '12歳以下の場合' do
      let(:age) { 12 }
      it 'ひらがなで答えること' do
        expect(user.greet).to eq 'ぼくはたろうだよ。'
      end
    end
    context '13歳以上の場合' do
      let(:age) { 13 }
      it '漢字で答えること' do
        expect(user.greet).to eq '僕はたろうです。'
      end
    end
  end
end

ここでは、

  1. expect(user.greet).to eqの部分でuserをさがす。
  2. let(:user) { User.new(params) }が呼ばれ、
      ここでparamsをさがす。
  3. let(:params) { { name: 'たろう', age: age } }が呼ばれ、次はageをさがす。
  4. let(:age) { 12 }がよばれる。

のようにしてletが呼び出される。

###事前に実行されるlet!
let!を使うとexample*の実行前にlet!で定義した値が作られる。

RSpec.describe Blog do
  #事前にblogが作られるためexpectでエラーにならない。
  let!(:blog) { Blog.create(title: 'RSpec必勝法', content: 'あとで書く') }
  it 'ブログの取得ができること' do
    expect(Blog.first).to eq blog
  end
end

#subjectの使い方
subjectを使えば同じエクスペクテーションを一つにまとめることができる。

#12歳以下のとき
expect(user.greet).to eq 'ぼくはたろうだよ。'
#13歳以上のとき
expect(user.greet).to eq '僕はたろうです。'

#上の二つを次のようにまとめる
subject { user.greet } #subjectで宣言し、
is_expected.to eq 'ぼくはたろうだよ。' #is_expected.toでテスト

さらに、itを省略して、次のようにかける。

RSpec.describe User do
  describe '#greet' do
    let(:user) { User.new(name: 'たろう', age: age) }
    subject { user.greet }
    context '12歳以下の場合' do
      let(:age) { 12 }
      it { is_expected.to eq 'ぼくはたろうだよ。' }
    end
    context '13歳以上の場合' do
      let(:age) { 13 }
      it { is_expected.to eq '僕はたろうです。' }
    end
  end
end

#itのエイリアス specify, example
itの代わりにspecifyexampleが使える。

# それ(it)はユーザー名を返す
it 'returns user name' do
  # ...
end

# 会社は社員を持つことを仕様として明記(specify)する
specify 'Company has employees' do
  # ...
end

# fizz_buzzメソッドの実行例(example)
example '#fizz_buzz' do
  # ...
end

#RSpecの高度な機能

shared_example と it_behaves_like

shared_exampleit_behaves_likeを使えば、exampleの再利用ができる。 

RSpec.describe User do
  describe '#greet' do
    
    #省略

    shared_examples '大人のあいさつ' do
      it { is_expected.to eq '僕はたろうです。' }
    end
    context '13歳の場合' do
      let(:age) { 13 }
      it_behaves_like '大人のあいさつ'
    end
    context '100歳の場合' do
      let(:age) { 100 }
      it_behaves_like '大人のあいさつ'
    end
  end
end

shared_example "foo" do ... endで再利用したいexampleを定義し、it_behaves_like "foo"で呼び出す。

###shared_context と include_context
shared_exampleit_behaves_likeのように、
contextの再利用には、shared_contextinclude_contextが使える。

RSpec.describe User do
  let(:user) { User.new(name: 'たろう', age: age) }

 #これらの記述でlet(:age)の繰り返しをなくす
  shared_context '12歳の場合' do
    let(:age) { 12 }
  end
  shared_context '13歳の場合' do
    let(:age) { 13 }
  end

  describe '#greet' do
    subject { user.greet }
    context '12歳以下の場合' do
      include_context '12歳の場合'
      it { is_expected.to eq 'ぼくはたろうだよ。' }
    end
    context '13歳以上の場合' do
      include_context '13歳の場合'
      it { is_expected.to eq '僕はたろうです。' }
    end
  end

  describe '#child?' do
    subject { user.child? }
    context '12歳以下の場合' do
      include_context '12歳の場合'
      it { is_expected.to eq true }
    end
    context '13歳以上の場合' do
      include_context '13歳の場合'
      it { is_expected.to eq false }
    end
  end
end

shared_context "foo" do ... endで再利用したいコンテキスト宣言し、contextの中でinclude_context "foo"を使って呼び出す。

#スキップさせたいとき
RSpecではテストを一旦置いときたいときにスキップできる。

xを使う

itdescribeの前にxと書きxit, xdescribeとすることで、そのテストをスキップできる。(pending扱いになる。)

RSpec.describe '何らかの理由で実行したくないクラス' do
  #xexample, xspecify も使える。
  xit '実行したくないテスト' do
    expect(foo).to eq bar
  end
end

#describeをスキップ
xdescribe '四則演算' do
  
end

# contextをスキップ
xcontext '管理者の場合' do
  
end

テストは後で書く、中身のない it

it "foo" do ... enddo ... endを省略することでpendingにすることができる。

RSpec.describe User do
  describe '#good_bye' do
    context '12歳以下の場合' do
      #do ... end を省略
      it 'ひらがなでさよならすること'
    end
end
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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?