I'm a little confused about what is going on with the scaffold controller specs that rspec generates. It seemed to be making sense until I added authorization to my app and now I need to update my tests.
MyClass.stub(:new).with('these' => 'params') { mock_my_class(:save => true) }
In my controller I merge a hash into params when creating a new record (it needs the current_user id to be valid). MyClass.new(params[:my_class].merge(:user_id => current_user.id))
Test Fails
expected: ({"these"=>"params"})
got: ({"these"=>"params", "user_id"=>315})
It makes sense that the test fails because the new method receives params it didn't expect. It expected to receive {'these' => 'params'} but it actually received {'these' => 'params', 'user_id' => 1234}
So my natural reaction is to adjust the test because the new method should receive {'these' => 'params', 'user_id' => 1234} and return the mock object.
So I add to the test as follows:
MyClass.stub(:new).with({'these' => 'params', 'user_id' => @user.id}) { mock_my_class(:save => true) }
Here is where I get thrown through a loop. The output of the test is as follows:
expected: ({"these"=>"params", "user开发者_开发技巧_id"=>298})
got: ({"these"=>"params"})
It seems as if a successful test is magically evading me. I'm sure there is a logical reason for these results, but I can't seem to figure them out.
Any help? :)
note:
The rspec site says the following:
Account.should_receive(:find).with("37").and_return(account)
or
Account.stub!(:find).and_return(account)
This is easy enough to follow it just seems odd the the scaffold generated would not contain these methods (unless I botched something which is possible (: )
Passes
login_admin
describe "with valid params" do
it "assigns a newly created forum_sub_topic as @forum_sub_topic" do
ForumSubTopic.stub(:new) { mock_forum_sub_topic(:save => true) }
ForumSubTopic.should_receive(:new).with({"these"=>"params", "user_id"=> @admin.id}) #PASS!
post :create, :forum_sub_topic => {'these' => 'params'}
assigns(:forum_sub_topic).should be(mock_forum_sub_topic) #PASS!
end
end
Fails
login_admin
describe "with valid params" do
it "assigns a newly created forum_sub_topic as @forum_sub_topic" do
ForumSubTopic.stub(:new).with({'these' => 'params', 'user_id' => @user.id}) { mock_forum_sub_topic(:save => true) }
post :create, :forum_sub_topic => {'these' => 'params'}
assigns(:forum_sub_topic).should be(mock_forum_sub_topic)
end
end
"Never trust a junkie", as the saying goes. One could also say, "never trust a scaffold".
OK, that's being a little bit too harsh. The scaffold does its best to figure out which parameters will work for the models/controllers you are generating, but it doesn't know about nested resources (which is what I assume you are using), so it won't generate the user_id
in the params hash. Add that:
post :create, :forum_sub_topic => {:user_id=>@user.id}
The these_params
key is generated as an example — remove it and add whatever parameters are needed for the controller to create a MyClass
.
Regarding the with
option: stub
and should_receive
will only stub out messages that meet the specified conditions, i.e. if you do:
MyClass.stub(:new) {mock_model(MyClass,:save=>true)}
Then MyClass will respond to any new
message with the mock. If, on the other hand, you do:
MyClass.stub(:new).with({:bogus=>37}) {mock_model(MyClass,:save=>true)}
Then MyClass will only respond to new
when it also receives {:bogus=>37}
as an argument.
精彩评论