2017-08-28 9 views
0

私は私のコントローラをテストしていとARクエリ生成文字列があります: current_user.providers.find(params[:id])が。テストするオブジェクトを正確に返す必要があります。それ以外の場合は、コントローラーが私の仕様とは異なるリファレンスを取得し、allow(provider).to receive(:recreate)のようなスタブが機能しません。receive_message_chainと臭いコード

これを行うには、receive_message_chainを次のように使用してください。 allow(provider.user).to receive_message_chain(:providers, :find => provider)しかし、rspecのドキュメントsaysを使用して、receive_message_chainのコードを使用することをお勧めします。 さらに、current_user.providers.find(otherid)に別のIDを付けて別のオブジェクトを取得する必要があるかもしれないと思うので、それはもう役に立たないでしょう。

は、より良い、それを行うための方法はありますか?私はすでにallow_any_instance_ofを避けることができました。それもまた臭いと考えられていますので、これも避ける方法があると信じています。私はそれを見ることはできません。 何があるなら、私は少なくともreceive_message_chainwithのようなものを追加する方法はありませんかしら?

===========

私はちょうど私のコントローラのupdateメソッドをテストしようとしています。

# app/controllers/restream/facebooks_controller.rb 
class Restream::FacebooksController < Restream::BaseController 
    def update 
    current_user.providers.find(params[:id]) 

    if @fb.update_attributes(facebook_params) 
     if event_changed? 
     @fb.recreate 
     else 
     @fb.update 
     end 
     redirect_to restreams_path 
    else 
     render 'edit' 
    end 
    end 
end 

#spec/controllers/restream/facebooks_controller_spec.rb 

require 'rails_helper' 

describe Restream::FacebooksController do 
    let!(:facebook) { create(:restream_facebook) } 
    let!(:restream) { facebook.restream } 

    before do 
    login(restream.user) 
    end 

    describe '#update' do 
    let!(:params_hash) { { 
     :title   => facebook.title, 
     :privacy  => facebook.privacy, 
     :destination => facebook.destination, 
     :destination_id => facebook.destination_id, 
     :description => facebook.description 
     } } 
    let!(:request_hash) { { 
      :restream_facebook => params_hash, 
      :id     => facebook.id 
     } } 

    before do 
     allow(facebook.user). 
     to receive_message_chain(:providers, :find => facebook) 
     allow(facebook).to receive(:update) 
     allow(facebook).to receive(:recreate) 
    end 

    context 'updates' do 
     it 'title' do 
     params_hash[:title] = SecureRandom.hex(2) 
     post :update, request_hash 

     expect(facebook.reload.title).to eq params_hash[:title] 
     end 
    end 
    end 
end 

答えて

0

あなたのコントローラは、チェーンからcurrent_userを除去することによって、同じように動作しますか? Provider.find(params[:id])その方法では、連鎖していないメソッドとテストするより簡単なコードが少なくなります。私はcurrent_user.providers.findの鎖がちょうどProvider.find以上をしているとは思わない。

+0

私は永久に 'current_user'を削除することはできません。そして、私は 'Rails.env.test? 'のような文字列も望んでいません。それとも私は他のやり方でやることができるのですか?それはcurrent_user'がそれに上のタック '持つと同じように動作するはずのように:あなたはあなたのポストの最初の文で参照 – Ngoral

+0

コントローラのメソッドは、私は' Provider.find([ID]のparams)で置き換えることをお勧め。それが同じ振る舞いを生み出すならば、メソッド連鎖が少なくて済むので、テストコードが簡単に実行できるようです。それはおそらく、私の前提にとらわれている可能性があるので、より多くのコード例であなたの投稿を編集するのに役立つだろう。 – abax

+0

私は簡単にコードサンプルを追加することができますが、ちょうど正確には分かりません。 私は 'allow(Provider).to receive(:find).with(provider.id).and_return provider'を使用しようとしましたが、それは何らかの理由で動作しませんでした。 – Ngoral

0

receive_messaged_chainは匂いであってもよいが、テスト・コントローラは、はるかに大きな悪臭のときダブルスを使用することができます。

あなたが任意のコントローラのアクションコードを提供しなかったので、私はあなたの一般的な例を与えるだろう:deleteメソッドが呼び出された場合

def destroy 
    @provider = current_user.providers.find(params[:id]) 
    @provider.delete 
end 

はテストしないでください。オブジェクトがDBから消滅したかどうかをテストします。例:

let(:current_user) { FactoryGirl.create(:user) } 
let!(:provider) { FactoryGirl.create(:provider, user: current_user } 
it do 
    delete :destroy, id: provider.id 
    expect(Provider.find(provider.id).to raise_error(ActiveRecord::RecordNotFound) # writing from memory, don't remember exactly how the exception is called 
end 

# or 

it do 
    expect { delete :destroy } 
    .to change{ Provider.where(id: provider.id).count }.from(1).to(0) 
end 

などです。一般的には、最後の手段としてダブルスを使用したいと考えています。実際の効果の観点からコードをテストする方法を考えてみてください。これは、すべての統合テスト(コントローラの場合)に適用されます。単体テストを書いており、分離が必要な場合は、この分離を達成するために物を嘲笑してください。

+0

実際、 'update'メソッドをテストしていて、必要なオブジェクトが更新されていることを確認したかったのです。私は今いくつかのコードを提供します。しかし、私はちょうど 'facebookをテストすることができないことが分かったと思う。title'が、Restream :: Facebook.find(facebook.id).title'があります。たぶんそうだ。 – Ngoral

+0

また、「facebook」のメソッドを初期化したり再作成したりするのは間違いないと思います。そして、もし私が 'provider.find'の結果を「置き換える」ことができなければ、それらのメソッドをスタブするために' allow_any_instance_of'を使う必要があります。だから私は今でも見つけたものを私が必要とするものと取り替える必要があります。 – Ngoral

+0

@ Ngoralその場合、あなたは正しいです。スタブファインダーメソッド(Something.findまたは何か、received_message_chainのproviders.find)を使用してテストで設定したモックを返し、そのモックで何らかのメソッドが呼び出されたことを確認します。私は 'receive_message_chain'を使うことは、あなたがテストしているものを明確にしている限り大きな問題ではないと思います。 – meta

関連する問題