RSpec

【RSpec】テストをpendingしたい場合はメソッドの頭文字にxを付ければ良い話

RSpec

 

今回はRSpecでテストをpending(保留)する方法についてまとめたいと思います。プルリクエスト出したいけどこのテストは一旦保留にしたい、テストが未完成だけどとりあえずCircle Ciのチェックをパスしてプルリクエストを出したいといった状況などに使える方法です。

コードをわざわざコメントアウトする必要がなくなるね。

テストコード例

今回はUserモデルのnameとname_kanaのバリデーションチェックを行うシンプルなモデルテストを書いてみました。データ作成にはFactoryBotを使用しています。

class User < ApplicationRecord
  validates :name, :name_kana, presence: true
end
FactoryBot.define do
  factory :user do
    name { "田中太朗" }
    name_kana { "タナカタロウ" }
  end
end
require 'rails_helper'

RSpec.describe User, type: :model do
  it "nameとname_kanaが存在する" do
    user = FactoryBot.build(:user)
    expect(user).to be_valid
  end

  it "nameが空の場合" do
    user = FactoryBot.build(:user, name: nil)
    user.valid?
    expect(user.errors[:name]).to include("can't be blank")
  end

  it "name_kanaが空の場合" do
    user = FactoryBot.build(:user, name_kana: nil)
    user.valid?
    expect(user.errors[:name_kana]).to include("can't be blank")
  end
end

 

上記のテストコードを実行すると3つのexamplesが成功するはずです。

% bundle exec rspec spec/models/user.rb

User
  nameとname_kanaが存在する
  nameが空の場合
  name_kanaが空の場合

Finished in 0.09137 seconds (files took 1.56 seconds to load)
3 examples, 0 failures

【xdescribe】テスト全体をpending

テスト全体をpendingにするには、describeをxdescribeに編集することで可能になります。ここではUserモデルのテスト全体をpendingにしてみます。

require 'rails_helper'

RSpec.xdescribe User, type: :model do
  it "nameとname_kanaが存在する" do
    user = FactoryBot.build(:user)
    expect(user).to be_valid
  end

  it "nameが空の場合" do
    user = FactoryBot.build(:user, name: nil)
    user.valid?
    expect(user.errors[:name]).to include("can't be blank")
  end

  it "name_kanaが空の場合" do
    user = FactoryBot.build(:user, name_kana: nil)
    user.valid?
    expect(user.errors[:name_kana]).to include("can't be blank")
  end
end
% bundle exec rspec spec/models/user.rb

User
  nameとname_kanaが存在する (PENDING: Temporarily skipped with xdescribe)
  nameが空の場合 (PENDING: Temporarily skipped with xdescribe)
  name_kanaが空の場合 (PENDING: Temporarily skipped with xdescribe)

Pending: (Failures listed here are expected and do not affect your suite's status)

  1) User nameとname_kanaが存在する
     # Temporarily skipped with xdescribe
     # ./spec/models/user.rb:4

  2) User nameが空の場合
     # Temporarily skipped with xdescribe
     # ./spec/models/user.rb:9

  3) User name_kanaが空の場合
     # Temporarily skipped with xdescribe
     # ./spec/models/user.rb:15


Finished in 0.00657 seconds (files took 3.2 seconds to load)
3 examples, 0 failures, 3 pending

【xcontext】テストの一部をpending

全体ではなくテストの一部をpendingにしたい場合は、contextで括り、pendingにしたいcontextをxcontextに変更します。ここでは異常系のテストをpendingにしてみます。

require 'rails_helper'

RSpec.describe User, type: :model do
  context "正常系" do
    it "nameとname_kanaが存在する" do
      user = FactoryBot.build(:user)
      expect(user).to be_valid
    end
  end

  xcontext "異常系" do
    it "nameが空の場合" do
      user = FactoryBot.build(:user, name: nil)
      user.valid?
      expect(user.errors[:name]).to include("can't be blank")
    end

    it "name_kanaが空の場合" do
      user = FactoryBot.build(:user, name_kana: nil)
      user.valid?
      expect(user.errors[:name_kana]).to include("can't be blank")
    end
  end
end
% bundle exec rspec spec/models/user.rb

User
  正常系
    nameとname_kanaが存在する
  異常系
    nameが空の場合 (PENDING: Temporarily skipped with xcontext)
    name_kanaが空の場合 (PENDING: Temporarily skipped with xcontext)

Pending: (Failures listed here are expected and do not affect your suite's status)

  1) User 異常系 nameが空の場合
     # Temporarily skipped with xcontext
     # ./spec/models/user.rb:12

  2) User 異常系 name_kanaが空の場合
     # Temporarily skipped with xcontext
     # ./spec/models/user.rb:18


Finished in 0.07004 seconds (files took 1.57 seconds to load)
3 examples, 0 failures, 2 pending

【xit】テストをskip

pendingとは意味が異なりますが、テストをskipにすることもできます。

pendingはテスト失敗時にのみ保留中にしてくれますが、skipはテスト成功失敗に関わらずテストを実行しないという違いがあります。

テストをskipしたい場合はitをxitに変更します。ここでは「nameとname_kanaが存在する」というテストをskipしてみます。

require 'rails_helper'

RSpec.describe User, type: :model do
  it "nameとname_kanaが存在する" do
    user = FactoryBot.build(:user)
    expect(user).to be_valid
  end

  xit "nameが空の場合" do
    user = FactoryBot.build(:user, name: nil)
    user.valid?
    expect(user.errors[:name]).to include("can't be blank")
  end

  it "name_kanaが空の場合" do
    user = FactoryBot.build(:user, name_kana: nil)
    user.valid?
    expect(user.errors[:name_kana]).to include("can't be blank")
  end
end
% bundle exec rspec spec/models/user.rb

User
  nameとname_kanaが存在する
  nameが空の場合 (PENDING: Temporarily skipped with xit)
  name_kanaが空の場合

Pending: (Failures listed here are expected and do not affect your suite's status)

  1) User nameが空の場合
     # Temporarily skipped with xit
     # ./spec/models/user.rb:9


Finished in 0.10042 seconds (files took 2.09 seconds to load)
3 examples, 0 failures, 1 pending

まとめ

  • RSpecでテストをpendingにするには「x」を付与すればよい
  • テスト全体をpendingしたい場合はdescribeをxdescribeにする
  • テストの一部をpendingしたい場合はcontextをxcontextにする
  • テストをskipしたい場合はitをxitにする

参考

使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」

 

 

今回はRSpecでテストをpending(保留)する方法について解説しました。テストが増えれば増えるほどpendingを使う機会が増えるため、覚えておいて損はないと思います。