Skip to content

Instantly share code, notes, and snippets.

@zaru
Created July 12, 2017 07:12
Show Gist options
  • Select an option

  • Save zaru/2c102235b952541c57854778e8cc6beb to your computer and use it in GitHub Desktop.

Select an option

Save zaru/2c102235b952541c57854778e8cc6beb to your computer and use it in GitHub Desktop.
他のクラスに依存しているクラスのテスト・モックスタブ
class A
def perform
b = B.new
b.execute
end
end
class B
def execute
"本物"
end
end
it "" do
mock = B.new
allow(B).to receive(:new).and_return(mock)
allow(mock).to receive(:execute).and_return("stub method")
A.new.perform
expect(mock).to have_received(:execute).once
end
@JunichiIto
Copy link

newメソッドをモックにするのはちょっと気持ち悪いので、可能であればモックを差し込みやすいようにクラスAの実装を変更する方がいいかなと思います。

もしクラスAを変更できない状況なのであれば、Bのnewをモックにする(またはallow_any_instance_ofを使う)のはやむを得ないかもしれません。

class A
  def perform
    b = generate_b
    b.execute
  end

  # モックを差し込めるようにメソッドを用意する
  def generate_b
    B.new
  end
end

class B
  def execute
    '本物'
  end
end

describe do
  example do
    a = A.new
    mock = double :b
    # モックを差し込む
    allow(a).to receive(:generate_b).and_return(mock)
    # モックが呼ばれることの検証と、戻り値の設定を同時に行う
    expect(mock).to receive(:execute).once.and_return('stub method')
    # 念のためモックの結果が返ってくることも検証しておく
    expect(a.perform).to eq 'stub method'
  end
end

@JunichiIto
Copy link

@zaru
Copy link
Author

zaru commented Jul 12, 2017

ありがとうございます! 参考になります。

今回の案件だと、Aクラスに手を入れにくい状況だったので、外からモックを無理やり作る方向で模索していました。指摘したもらった通りAクラス自体を改善していくのが良いと思います。

また、 allow_any_instance_of を使おうかと思ったんですが、この記事を読んで止めました。

rspecでallow-any-instance-ofは使わない方がよい、が身に沁みたので別の方法で試してみる

@JunichiIto
Copy link

今回の案件だと、Aクラスに手を入れにくい状況だったので、外からモックを無理やり作る方向で模索していました。指摘したもらった通りAクラス自体を改善していくのが良いと思います。

なるほど、それなら仕方ないですね。

また、 allow_any_instance_of を使おうかと思ったんですが、この記事を読んで止めました。

はい、allow_any_instance_ofはできるだけ使わない方がいいですね。(といいつつ、僕は今もたまに使いますがw)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment