43

Rspecテストを書くとき、私はしばしばに不満を感じshould_receiveます。邪魔にならない代替手段があるかどうか知りたいのですが。

例えば:

describe "making a cake" do
  it "should use some other methods" do
    @baker.should_receive(:make_batter)
    @baker.make_cake
  end
end

toの呼び出しは適切な説明ですが、元のメソッドをマスクすることで機能し、実際にバッターを返さない限り続行できないshould_receiveため、コードが壊れます。だから私はそれをこれに変更します:should_receivemake_cakemake_batter

@baker.should_receive(:make_batter).and_return(@batter)

これは醜い理由です:

  • 正しく返されることをテストしているように見えますが、実際にはの偽のバージョンにそれを返すように強制しています。make_batter@battermake_batter
  • それは私に別々にセットアップすることを強制します@batter
  • 重要な副作用がある場合make_batter(コードの臭いである可能性があります)、私もそれらを起こさなければなりません。

should_receive(:make_batter)それがメソッド呼び出しを検証し、それを元のメソッドに渡すことを望みます。より良い分離テストのためにその動作をスタブしたい場合は、明示的に行います@baker.stub(:make_batter).and_return(@batter)

should_receive元のメソッド呼び出しを妨げずに、のようなことを行う方法はありますか?私の問題は悪いデザインの症状ですか?

4

3 に答える 3

63

MyronMarstonがほのめかした元のメソッドに委任するためのより優れたAPIが実際にrspec-mocksv2.12.0に追加されたようです。

したがって、「オブジェクトがメッセージにどのように応答するかを妨げることなく、メッセージの有効期限を設定したい」ときはいつでも、これを簡単に行うことができます。

@baker.should_receive(:make_batter).and_call_original

これを追加してくれてありがとう、マイロン。

于 2013-02-04T19:12:28.650 に答える
11

should_receive次のように元のメソッドを実行できます。

@baker.should_receive(:make_batter, &@baker.method(:make_batter))

とは両方とも、ブロック実装の受け渡しshould_receivestubサポートします(つまり、メソッドが呼び出されたときに評価されます)。&@baker.method(:make_batter)元のメソッドオブジェクトへのハンドルを取得し、それをブロック実装として渡します。

FWIW、元のメソッドに委任するためのより優れたAPIを提供したいのですが(この問題を参照)、下位互換性を損なうことなくその機能を追加することは困難です。

于 2012-08-28T14:16:42.853 に答える
6

メソッドshould_receiveの実装の詳細をテストしているため、この問題が発生しています。make_cakeテストを作成するときは、一連の内部メソッド呼び出しではなく、動作のみに焦点を当てる必要があります。そうしないと、後でコードをリファクタリングすると、すべてのテストも大幅にリファクタリングされます。

クラスを個別にテストする場合は、モックとスタブが便利です。単体テストを作成するときは、テスト対象を他のオブジェクトから分離する必要があります。一度に複数のオブジェクトを操作する場合、両方が代用として機能します。この場合should_receive、メソッドを呼び出すことにより、テストサブジェクトがタスクを別のオブジェクトに正しく委任することを確認するために使用できます。

于 2012-08-28T13:56:35.147 に答える