🔥

【Rspec】expected ~ to have changed by 1, but was changed by 0

2024/04/08に公開

はじめに

Rspecを起動時、よく遭遇するエラーに発生したためメモ書きで共有
forms_validationのテストを記載している際に遭遇

エラー

expected `Schedule.count` to have changed by 1, but was changed by 0

エラー直訳

Schedule.count`が1変更されることを期待したが、0変更された

つまり

何らかの原因で「期待されるレコード数」が+1にならなかった

テスト

spec/requests/api/v1/admin/schedules/create_spec.rb

      let(:params) do
        {
          schedule: attributes_for(:schedule, :unpublished, :offline).merge(
            campaign_id: campaign.id,
            prefecture_id: prefecture.id,
            area_id: area.id,
            target_prefecture_ids: prefecture_ids,
            target_school_specialty_group_ids: school_specialty_group_ids,
            is_schedule: true,
            participant_limit: nil
          )
        }
      end
      
      it 'participant_limitがデフォルト値で作成される' do
        expect { request }.to change(Schedule, :count).by(+1)
        expect(Schedule.last.participant_limit).to eq(0)
      end

この時点でお分かりの方もいらっしゃるかもしれないが...

原因

participant_limitカラムにnilを設定されていること
これにより、テストが落ちてテーブル作成(+1)が行われていなかった

修正

以下を追記

let(:participant_limit) { Faker::Number.between(from: 0, to: 100) }

Fakerを使用
https://github.com/faker-ruby/faker

以下に修正

      let(:params) do
        {
          schedule: attributes_for(:schedule, :unpublished, :offline).merge(
            〜省略〜
            participant_limit: participant_limit # 変更
          )
        }
      end   

テストが正常に通りました🙌

テストコマンド

Dockerを使用

docker-compose run --rm app bundle exec rspec spec/requests/api/v1/admin/schedules/create_spec.rb

参考

https://qiita.com/nao0725/items/d932baa28edf3dced3c5

https://stackoverflow.com/questions/49242654/rspec-expected-count-to-have-changed-by-1-but-was-changed-by-0?newreg=8d526ded17414058b50d00082831a7a6

https://rspec.info/documentation/

補足(formsの修正事項)

今回のテスト目的

  • カラムの値がNullのとき、テーブルを作成しない
  • カラムの値が0のとき、テーブルを作成する
  • カラムが1以上の整数のとき、テーブルを作成する

元々のコード

participant_limit.positive?

def participant_limit?
    result = participant_limit.positive?
    errors.add(:participant_limit, 'は0以上の値を入力してください。') unless result
end

修正したコード(テストが通った)

participant_limit >= 0

def set_default_participant_limit
    self.participant_limit = 0 if participant_limit.nil?
end

def participant_limit?
  result = participant_limit >= 0
  errors.add(:participant_limit, 'は0以上の値を入力してください。') unless result
end

以下2つのコードの違い

participant_limit.positive?

  • オブジェクトが1以上の正の数値であることを要求

participant_limit >= 0

  • オブジェクトが0を含む0以上の数値であることを要求

合わせてこちらも勉強になりました!

以上です
ありがとうございました!

Discussion