RSpecでスタブを使う

f:id:utouto97:20210725220657j:plain

RSpecでスタブを使う方法

RSpecでスタブを使うには、allow(オブジェクト).to receive(:メソッド名).and_return(返り値)のようにします。
allowで対象のオブジェクトを,receiveで対象のメソッドを指定します。

それに続けて、and_returnで返り値を指定します。
and_returnの部分は、and_raiseとして例外を発生させることもできます。
このほかにも、and_yieldというのもあります。

RSpecでスタブを試す

実際に、RSpecでスタブを試してみます。

まず、今回利用したテストコード全体を貼ります。

class A
  def doSomething(count)
    count + 1
  end
end

class B
  def getCount
    rand(100)
  end
end

RSpec.describe A do
  a = A.new
  b = B.new

  context "スタブを利用しない" do
    example "doSomethingでインクリメントされる" do
      count = b.getCount
      result = a.doSomething(count)
      expect(result).to eq 1
    end
  end

  context "スタブを利用する" do
    example "doSomethingでインクリメントされる" do
      allow(b).to receive(:getCount).and_return(0)

      count = b.getCount
      result = a.doSomething(count)
      expect(result).to eq 1
    end
  end
end

A, Bの二つのクラスがあり、クラスAはdoSomethingで引数をインクリメントして返します。
クラスBは、getCountで乱数を返します。

クラスBのgetCountから値を受け取り、クラスAのdoSomethingに渡して、結果をテストします。
ここでの、テスト対象はクラスAとします。

スタブを利用しない場合は、

  1) A スタブを利用しない doSomethingでインクリメントされる
     Failure/Error: expect(result).to eq 1
     
       expected: 1
            got: 14
     
       (compared using ==)
     # ./spec/calc_spec.rb:21:in `block (3 levels) in <top (required)>'

と、テストに失敗しました。
Aに渡す引数は乱数であるため、その結果を正しく検証することができません。

そこで、スタブを利用し、BのgetCountの返り値を指定します。
ここでは、0を返すようにしています。

      allow(b).to receive(:getCount).and_return(0)

こうすると、BのgetCountは必ず0を返し、AのdoSomethingによりインクリメントされるため1になります。
そして、expect(result). to eq 1をパスします。

終わり