RSpecでsubjectを使用して、配列を
subject { user.errors[:name] } # user.errors[:name] は配列
このように検査時、配列の長さを取得する方法が分からなかったので調べました。
結論
rspec-its
のits
を使用する。
its(:size) { is_expected.to eq 3 }
のように書くとsubjectの検査対象の配列の長さを取得できます。
経緯
モデルのテストを書きました。
modelのコード↓
class User < ApplicationRecord validates :nickname, presence: true, length: { maximum: 32 }, format: { with: /\A[-0-9a-zA-Z#$%&()._]*\z/, message: 'には半角英数字と#$%&()-._のみ使用できます。' } end
テストは以下のようになります。(全て書くと長いので一部のみ抜粋)
require 'rails_helper' RSpec.describe User, type: :model do describe '#nickname' do context '空白のとき'do it 'エラーが出ること' do user = User.new(nickname: '') user.valid? expect(user.errors[:nickname]).to include("can't be blank") end end context '許可される文字の場合' do context '英大文字小文字数字#$%&()-._' do it 'エラーが出ないこと' do user = User.new(nickname: 'ARZatz809(_#-$%.&)') user.valid? expect(user.errors[:nickname]).to be_blank end end end context '許可されない文字の場合' do context '許可されていない文字"?"が含まれている場合' do it 'エラーが出ること' do user = User.new(nickname: 'correct?') user.valid? expect(user.errors[:nickname]).to include('には半角英数字と#$%&()-._のみ使用できます。') end end end end end
これを綺麗にすると以下のようになります。(参考: 使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」 - Qiita )
require 'rails_helper' RSpec.describe User, type: :model do describe '#nickname' do subject { user.errors[:nickname] } let(:user) { User.new(params) } let(:params) { {nickname: nickname} } before do user.valid? end context '空白のとき'do let(:nickname) { '' } it { is_expected.to include("can't be blank") } end context '許可される文字の場合' do context '英大文字小文字数字#$%&()-._' do let(:nickname) { 'ARZatz809(_#-$%.&)' } it { is_expected.to be_blank } end end context '許可されない文字の場合' do context '許可されていない文字"?"が含まれている場合' do let(:nickname) { 'correct?' } it { is_expected.to include('には半角英数字と#$%&()-._のみ使用できます。') } end end end end
繰り返しがなくなってすっきりしました。
ここでふと思いました。 このテストコード、対象のエラーが含まれることはチェックできるけど、想定外のエラーが(間違って)含まれることはテストできていないじゃん、と。
ここでの方針としては、
- includeでなく配列同士の比較を行う
- エラーの数をチェックする
などが思いつきます。今回は
- エラーの数をチェックする
方法にします。この方法をとることで、
- エラーの順番は問わず
- 想定外のエラーが間違って入っていることを防ぐ
ことができます。
さて、テストの対象はsubject
に書かれています。これのサイズを取得したい。
これにはits
を使用します。
RSpec3からits
はgemに分離されているのでインストールします。
Gemfile
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' gem 'rspec-its' # この行を追加 end
bundle installします。
テストを追加します。
its(:size) { is_expected.to eq 1 }
のように書くとuser.errors[:nickname].size
が1かどうかをテストすることができます。
RSpec.describe User, type: :model do describe '#nickname' do subject {user.errors[:nickname]} # 略 context '空白のとき'do let(:nickname) { '' } it { is_expected.to include("can't be blank") } its(:size) { is_expected.to eq 1 } # 追加 end context '許可される文字の場合' do context '英大文字小文字数字#$%&()-._' do let(:nickname) {'ARZatz809(_#-$%.&)'} it { is_expected.to be_blank} end end context '許可されない文字の場合' do context '許可されていない文字"?"が含まれている場合' do let(:nickname) {'correct?'} it { is_expected.to include('には半角英数字と#$%&()-._のみ使用できます。')} its(:size) { is_expected.to eq 1 } # 追加 end end end end
以上でsubjectに指定した配列のサイズ(長さ)をテストすることができました。