1

プロジェクト、タスク、およびサブタスクに属することができるディスカッション (ポリモーフィック リソース) があります。次の作成アクションのテストに問題があります。

 26   def create               
 27     @discussion = @parent.discussions.build(params[:discussion])
 28     @discussion.user_id = current_user.id
 29     if @discussion.save    
 30       current_user.discussions.push(@discussion)
 31       redirect_to [@parent, @discussion], :notice => 'Discussion started' 
 32     else                   
 33       render 'new'         
 34       flash.now[:alert] = 'Unable to start discussion'
 35     end                    
 36   end

これらは作成アクションの前に発生するフィルターの前です (これらは必要なものを見つけます)

 63   private
 64 
 65   def find_cached_parent_or_from_something_id
 66     @parent || find_parent_from_something_id # this does a bit of caching
 67   end
 68 
 69   def find_parent_from_something_id
 70     @parent = nil
 71     params.each do |name, value|
 72       if name =~ /(.+)_id$/
 73         @parent = name.humanize.constantize.find(value)
 74       end
 75     end
 76     @parent
 77   end
 78
 79   def find_project_from_parent_belonging_project
 80     @project = @parent.belonging_project
 81     unless current_user.projects.include?(@project)
 82       redirect_to projects_path
 83       flash[:alert] = msg_page_not_found
 84     end
 85   end

ご覧のとおり、親と必要なすべての変数を見つけることができます。create アクションのRSpecコントローラ テストは次のようになります

104         it "can create discussion on project using valid attributes" do                                                                   
105           lambda do
106             post :create, :project_id => project,         
107                           :discussion => valid_attributes
108             flash[:notice].should == 'Discussion started'
109           end.should change(Discussion, :count).by(1)                                                                                     
110         end
111   
112         it "can create discussion on task using valid attributes" do                                                                      
113           lambda do
114             post :create, :task_id => task,               
115                           :discussion => valid_attributes
116             flash[:notice].should == 'Discussion started'
117           end.should change(Discussion, :count).by(1)                                                                                     
118         end
119 
120         it "can create discussion on subtask using valid attributes" do                                                                   
121           lambda do
122             post :create, :subtask_id => subtask,         
123                           :discussion => valid_attributes
124             flash[:notice].should == 'Discussion started'
125           end.should change(Discussion, :count).by(1)                                                                                     
126         end

しかし、次のテストに沿って、すべての親に関するディスカッションの作成をできるだけ DRY としてテストしたいと思います。

104         ['project', 'task', 'subtask'].each do |parent|
105           it "can create discussion on #{parent} using valid attributes" do
106             lambda do      
107               post :create, :parent_id => parent,
108                             :discussion => valid_attributes 
109               flash[:notice].should == 'Discussion started'
110             end.should change(Discussion, :count).by(1)
111           end
112         end

このテストを正しく書くには?

私はFactoryGirlを使用しています。上記のテストは > NameError: uninitialized constant Parent を返します

また、これを行うためのより良い方法/慣行がある場合は、必ず、私を修正してください:)

編集:以下の受け入れられた回答を使用して問題を解決しましたが、非常によく似た別の問題に出くわしました...

142           it "can access show action for discussion for #{parent}" do
143             get :show, :"#{parent}_id" => self.send(parent),
144                        :id => "disucussion_by_another_user_for_#{parent}"    
146             response.should be_successful   
147           end

この :id パラメータは間違って書かれています... 正しく書くのを手伝ってくれませんか? (このdiscussion_by_another_user_for_#{parent}は、私が定義した3つの異なるファクトリです...)

これは私の工場がどのように見えるかです:

16   let!(:discussion_by_another_user_for_project) { FactoryGirl.create(:discussion,
 17                                                                      :user => another_user,
 18                                                                      :discussionable => project) }
 19   let!(:discussion_by_another_user_for_task) { FactoryGirl.create(:discussion,
 20                                                                      :user => another_user,
 21                                                                      :discussionable => task) }
 22   let!(:discussion_by_another_user_for_subtask) { FactoryGirl.create(:discussion,
 23                                                                      :user => another_user,
 24                                                                      :discussionable => subtask) }
4

2 に答える 2

2

私は過去にそのような「トリック」を実行しようとして同様のジレンマを経験しましたが、あなたは私と同じ間違いを犯しています. 一度に 1 つのことだけをテストする必要があります。そうすれば、テストが失敗したときに何がうまくいかなかったのかがわかります。あなたがやろうとしているのは、1 つのテストで 3 つの異なることをテストすることであり、これはテストの目的を無効にします。混乱を招く 1 つの DRY テストではなく、テスト対象をテストする 3 つの「非 DRY」テストを残す必要があります。

そうは言っても、次のようなことを試すことができますが、失敗した場合は、テストコードの両方をデバッグして、どちらが間違っているかを知る必要があるという問題があります。

let!(:project) { FactoryGirl.create(:project) }
let!(:task) { FactoryGirl.create(:task) }
let!(:subtask) { FactoryGirl.create(:subtask) }

it "can create discussion on #{parent} using valid attributes" do
  parents = [project, task, subtask]
  parents.each do |parent|
    expect {
      post :create, :parent_id => parent,
                    :discussion => valid_attributes
      flash[:notice].should == 'Discussion started'
    }.to change(Discussion).by(3)
  end
end

注: 古いバージョンの RSpec を使用している場合は、「expect」を「lambda」に変更してください。

お役に立てれば

于 2012-06-14T23:35:15.393 に答える
1

私はあなたがほとんどそこにいたと思います:

["project", "task", "subtask'].each do |parent|
  it "can create discussion on #{parent} using valid attributes" do                                                                      
    lambda do   
      post :create, :"#{parent}_id" => self.send(parent),               
                    :discussion => valid_attributes
      flash[:notice].should == 'Discussion started'
    end.should change(Discussion, :count).by(1)                                                                                     
  end
end

お役に立てれば。

[編集] あなたの追加の質問: 単なる文字列を渡すことが実際にオブジェクトを作成するとどのように信じているのかよくわかりません. 次のように、FactoryGirl を使用してオブジェクトを作成します。

FactoryGirl.create(:factory_name)

したがって、それを考慮すると、テストは次のようになります。

it "can access show action for discussion for #{parent}" do
  discussion_by_another_user = FactoryGirl.create("discussion_by_another_user_for_#{parent}".to_sym)    
  get :show, :"#{parent}_id" => self.send(parent),
      :id => discussion_by_another_user.id
  response.should be_successful   
end

もちろん、パラメーターをインライン化することもできますがdiscussion_by_another_user、これはもう少し読みやすいと思います。お役に立てれば。

[編集] 質問を明確にした後: これは実際には、以前に尋ねたものと完全に同じです。文字列を作成しますが、実際には文字列は呼び出したいメソッドであり、前と同様に次のように記述します。

it "can access show action for discussion for #{parent}" do
  get :show, :"#{parent}_id" => self.send(parent),
             :id => self.send("discussion_by_another_user_for_#{parent}")
  response.should be_successful   
end

HTH

于 2012-06-15T13:51:09.383 に答える