rspecでrake task系のユニットテストで、onceなどのメソッド呼び出し回数チェックを使用していた。
それらのユニットテストをそれ単体で実行すると成功するが、テストを通して全件実行すると失敗する。
検証したところ、spec/lib/tasks/xxx_spec.rb で以下のようにrake taskを呼び出すためにロードしているが、 Rake::Task[task_name].invoke がこのコードを読み込んだ回数分、指定のタスクを実行していた。
before(:all) do Rails.application.load_tasks end
このため、同様のrake task系テストをまとめているディレクトリ配下のユニットテストを通しで実行すると、回数を検証するonceなどを使用しているitブロックで複数回rake叩いた挙動になってしまい、テストに失敗する。
例)
spec/aaa_task_spec.rb
before(:all) do Rails.application.load_tasks end context 'HogeClass#foo' do it { expect(HogeClass).to receive(:foo).once.with(kind_of(RuntimeError)) } end
spec/bbb_task_spec.rb
before(:all) do Rails.application.load_tasks end context 'FugaClass#foo' do it { expect(FugaClass).to receive(:foo).once.with(kind_of(RuntimeError)) } end
spec/ccc_task_spec.rb
before(:all) do Rails.application.load_tasks end context 'HogeClass#foo' do it { expect(HogeClass).to receive(:foo).once.with(kind_of(RuntimeError)) } end
rspec spec/
- > 1) HogeClass#foo
Failure/Error: expect(HogeClass).to receive(:foo).once.with(kind_of(RuntimeError))
(HogeClass (class)).foo(kind of RuntimeError)
expected: 1 time with arguments: (kind of RuntimeError)
received: 2 times
...
※load_tasksを呼び出す回数ずつ増える
解決策の例
1)各ファイルでのタスク読み込みをやめてspec_helperなどで一回だけ呼ぶようにする
2)タスク読み込みをまとめて行うのではなく、都度Rake.application.rake_requireする
→rails_helperにて一回だけ呼ぶように変更