RSpecでモックを使う
RSpecでモックオブジェクトを作る
doubleでモックを作る
RSpecでモックオブジェクトを作成するには、double
を使います。
mock_a = double(A)
↑のようにすることで、モックオブジェクトを作成することができます。
スタブでメソッドを付与
double
で作ったモックは、メソッドをもっていないので、スタブを使って仮のメソッドを設定してあげます。
allow(a).to receive(:f).and_return(1234)
RSpecでモックを試してみる
次のようなクラスAとクラスBを準備します。
class A def doSomething b = B.new b.getCount() end end class B def getCount() pp "called B.getCount()" rand() end end
まずは、モックを利用せずにテストを書きます。
RSpec.describe A do context "モックを利用しない場合" do example "getCountが呼び出される" do a = A.new expect(a.doSomething()).to eq 0 end end end
結果は次のようになりました。
"called B.getCount()" F Failures: 1) A モックを利用しない場合 getCountが呼び出される Failure/Error: expect(a.doSomething()).to eq 0 expected: 0 got: 0.29231320169185815 (compared using ==) # ./spec/calc_spec.rb:24:in `block (3 levels) in <top (required)>' Finished in 0.01401 seconds (files took 0.07903 seconds to load) 1 example, 1 failure Failed examples: rspec ./spec/calc_spec.rb:18 # A モックを利用しない場合 getCountが呼び出される
"called B.getCount()"の文字列が表示されており、クラスBのメソッドgetCount()が呼び出されていることが確認できます。
これは、文字列を表示しているだけですが、例えば、ツイートを投稿するようなメソッドの場合、テストのたびにツイートされていては大変なことになります。
また、返り値はrand()
により取得しているため、テストするのが難しいです。
モックを使って書くと次のようになります。
RSpec.describe A do context "モックを利用" do example "getCountが呼び出される" do mock_b = double(B) allow(B).to receive(:new).and_return(mock_b) allow(mock_b).to receive(:getCount).and_return(0) a = A.new expect(a.doSomething()).to eq 0 end end end
結果は↓のようになります。
. Finished in 0.00508 seconds (files took 0.07579 seconds to load) 1 example, 0 failures
実際のクラスBではなく、かわりのもの(モック)がAの中で利用されています。
また、次の1行をテストの末尾に加えることで、mock_b
のgetCount()
メソッドが1回呼ばれたことをテストできます。
expect(mock_b).to have_received(:getCount).once
exactly(n).times
を使うことで、n回呼ばれたことをテストできます。
expect(mock_b).to have_received(:getCount).exactly(n).times
終わり