🙄

RSpec で任意のメソッドが複数回呼ばれたかどうかと呼び出し順をテストする

2024/02/08に公開

前回の続きです。
前回は任意のメソッドが『1回呼ばれたかどうか』を判定していたんですが、『複数回呼ばれたかどうか』は次のようにテストする事ができます。

class X
  def hoge
    foo "homu"
    foo "mami"
    foo "mado"
  end

  def foo(str); end
end

require "rspec"

RSpec.describe X do
  describe "#hoge" do
    subject { x.hoge }

    let(:x) { X.new }

    # OK
    it do
      expect(x).to receive(:foo).with("homu")
      expect(x).to receive(:foo).with("mami")
      expect(x).to receive(:foo).with("mado")
      subject
    end

    # NG: 呼び出しが足りないと失敗する
    it do
      expect(x).to receive(:foo).with("homu")
      # expect(x).to receive(:foo).with("mami")
      expect(x).to receive(:foo).with("mado")
      subject
    end

    # NG: 呼び出しが過剰だと失敗する
    it do
      expect(x).to receive(:foo).with("homu")
      expect(x).to receive(:foo).with("mami")
      expect(x).to receive(:foo).with("mado")
      expect(x).to receive(:foo).with("saya")
      subject
    end
  end
end

こんな感じで単純に複数回 receive を使用すればテストする事ができます。

呼び出し順も担保するようにする

上記の書き方の場合は『呼び出し順』までは担保しません。
なので次のようなテストは成功します。

# OK: 順番が違っても成功する
it do
  expect(x).to receive(:foo).with("mami")
  expect(x).to receive(:foo).with("mado")
  expect(x).to receive(:foo).with("homu")
  subject
end

もし、メソッドの呼び出し順まで担保したい場合は次のように #ordered を呼び出すことで担保する事ができます。

# NG: 順番が違っていると失敗する
it do
  expect(x).to receive(:foo).with("mami").ordered
  expect(x).to receive(:foo).with("mado").ordered
  expect(x).to receive(:foo).with("homu").ordered
  subject
end
GitHubで編集を提案

Discussion