RSpecコントローラーでのnamed_scopeのスタブ
-
08-07-2019 - |
質問
このような状況では何も見つかりませんでした。このように定義された名前付きスコープを持つモデルがあります:
class Customer < ActiveRecord::Base
# ...
named_scope :active_customers, :conditions => { :active => true }
end
そして、私はコントローラーの仕様でそれを書き留めようとしています:
# spec/customers_controller_spec.rb
describe CustomersController do
before(:each) do
Customer.stub_chain(:active_customers).and_return(@customers = mock([Customer]))
end
it "should retrieve a list of all customers" do
get :index
response.should be_success
Customer.should_receive(:active_customers).and_return(@customers)
end
end
これは機能せず、失敗しています。顧客はactive_customersを期待しているが、0回受け取ったと言っています。 Indexアクションの実際のコントローラーには、 @customers = Customer.active_customers
があります。これを機能させるために何が欠けていますか?悲しいことに、RSpecに自分がやりたいことを伝える方法ではなく、仕様が何を説明しているのかを知っているので、テスト/仕様を考えてそれを書くよりも、コードを書く方が簡単であることがわかりました。
解決
スタブおよびメッセージの予想。メッセージの期待値は基本的にスタブであり、必要な定型応答を設定できますが、テスト対象のコードによって行われる呼び出しをテストします。対照的に、スタブはメソッド呼び出しに対する定型応答です。しかし、同じメソッドでスタブとメッセージ期待値を混在させてテストしないでください。悪いことが起こる ...
質問に戻りますが、ここで仕様を指定する必要があるのは2つ(またはそれ以上)です。
-
index
でget
を実行すると、CustomersControllerがCustomer#active_customers
を呼び出すこと。この仕様でCustomer#active_customers
が何を返すかは、実際には関係ありません。 -
active_customers
named_scopeは、実際にはactive
フィールドがtrue
である顧客を返します。
番号1を実行しようとしていると思います。その場合、スタブ全体を削除し、テストでメッセージの期待値を設定します。
describe CustomersController do
it "should be successful and call Customer#active_customers" do
Customer.should_receive(:active_customers)
get :index
response.should be_success
end
end
上記の仕様では、返されるものをテストしていません。それは仕様の意図であるため、問題ありません(ただし、仕様は動作とは対照的に実装に近すぎますが、それは別のトピックです)。 active_customers
への呼び出しで特に何かを返す場合は、先に進み、そのメッセージの期待値に .and_returns(@whatever)
を追加します。ストーリーの他の部分は、 active_customers
が期待どおりに動作することをテストすることです(つまり、実際にDBを呼び出すモデル仕様)。
他のヒント
次のように顧客レコードの配列を受け取ることをテストする場合は、モックの周りに配列があるはずです。
Customer.stub_chain(:active_customers).and_return(@customers = [mock(Customer)])
stub_chainは私にとって最適な方法です。
コントローラーを呼び出しています
ExerciseLog.this_user(current_user).past.all
このようにスタブすることができます
ExerciseLog.stub_chain(:this_user,:past).and_return(@exercise_logs = [mock(ExerciseLog),mock(ExerciseLog)])