I just spent a lot of time trying to get a test to pass that would not
pass no
matter what I did, and I finally decided to just do something really
simple to
verify that even that was working-- and it's not.
class PostsController < ApplicationController
def create
debugger # or binding.pry
end
end
--
#controllers/post_spec.rb
describe PostsController do
it "does not work" do
post :create
end
end
...
I never see the debugger prompt.. Can anyone PLEASE tell me why this is
not
working? In any other test, binding.pry or debugger interrupts the test
flow
and gives me access to the current scope of the debugger call.
Patrick J. Collins
http://collinatorstudios.com
on 2011-11-19 03:02
on 2011-11-19 05:14
On Nov 18, 2011, at 7:42 PM, Patrick J. Collins wrote: > end > > end > > ... > > I never see the debugger prompt.. Can anyone PLEASE tell me why this is not > working? In any other test, binding.pry or debugger interrupts the test flow > and gives me access to the current scope of the debugger call. Got any authentication in front of posts#create?
on 2011-11-19 05:56
Hi, On Sat, Nov 19, 2011 at 09:42, Patrick J. Collins <patrick@collinatorstudios.com> wrote: > end > > -- > > #controllers/post_spec.rb Shouldn't this be called `spec/controllers/posts_controller_spec.rb`? > I never see the debugger prompt.. Can anyone PLEASE tell me why this is not > working? In any other test, binding.pry or debugger interrupts the test flow > and gives me access to the current scope of the debugger call. Also as David suggests, perhaps it's a before_filter somewhere sending a response before the request is passed to PostsController#create. Mike
on 2011-11-19 19:48
> > I never see the debugger prompt.. Can anyone PLEASE tell me why this is not > > working? In any other test, binding.pry or debugger interrupts the test flow > > and gives me access to the current scope of the debugger call. > > Got any authentication in front of posts#create? Yeah, that was the problem! There was authentication in the ApplicationController and so I needed a skip_before_filter... Ok.. Taking this a step forward, what I really am trying to do is write tests that isolate some methods that are called by before_filters in my controller. So, lets say I have something like: class PostsController < ApplicationController before_filter :store_params, :only => :create def create ... create stuff end def store_params session[:post_params] = params[:post] end end What I would like to do is totally isolate store_params... So I'd do something like: describe "#store_params" do it "saves the post params for later" do session[:post_params].should be_blank post :create, { :post => { :fake_param => "foobar" } } session[:post_params][:fake_param].should == "foobar" end end ... Ok this is all groovy, except my tests will fail because fake_param is not an attribute on Post, and when it actually gets to the create method it essentially be trying to do Post.create!(:fake_param => "foobar")... So obviously I could choose to go about this differently and use a real post attribute-- but I am just curious if there is a way to isolate the testing of this method and make #create not even connected in any way? I was thinking originally that I should be able to do (prior to the post create call): PostsController.any_instance.stubs(:create).returns true But that doesn't seem to do anything... Patrick J. Collins http://collinatorstudios.com
on 2011-11-19 23:12
On Nov 19, 2011, at 9:57 AM, Patrick J. Collins wrote: > tests that isolate some methods that are called by before_filters in my > end > describe "#store_params" do > it "saves the post params for later" do > session[:post_params].should be_blank > > post :create, { :post => { :fake_param => "foobar" } } > > session[:post_params][:fake_param].should == "foobar" > end > end #store_params is not an "action", therefore I would make it private. Since it is used only by the #create action, I would spec it as part of the #create spec: describe '#create' do it 'stores the :post params' do post :create, { :post => { :fake_param => "foobar" } } session[:post_params][:fake_param].should == "foobar" end end > > ... Ok this is all groovy, except my tests will fail because fake_param is not > an attribute on Post, and when it actually gets to the create method it > essentially be trying to do Post.create!(:fake_param => "foobar")... So > obviously I could choose to go about this differently and use a real post > attribute-- but I am just curious if there is a way to isolate the testing of > this method and make #create not even connected in any way? > > I was thinking originally that I should be able to do (prior to the post create > call): You can, but you should mock Post.create!: describe '#create' do it 'stores the :post params' do Post.should_receive(:create!).and_return(true) post :create, { :post => { :fake_param => "foobar" } } session[:post_params][:fake_param].should == "foobar" end end
on 2011-11-20 00:06
> #store_params is not an "action", therefore I would make it private. I agree completely, and probably should have specified that in my sample code (it certainly is private in my real non-hypothetical implementation). > Since it is used only by the #create action, I would spec it as part of the #create spec: Well this came up for me because I have a bit of a complex controller which has several before_filters, and I wanted a clean way to really verify that each and every filter is doing what it should, so that's why I wanted to spec those individual methods. > You can, but you should mock Post.create!: > > describe '#create' do > it 'stores the :post params' do > Post.should_receive(:create!).and_return(true) > post :create, { :post => { :fake_param => "foobar" } } > session[:post_params][:fake_param].should == "foobar" > end > end Unfortunately, this project is using a plugin called "Decent Exposure" which does various magic to simplify controller code (and honestly has been a big headache). So, the create action actually calls post.save! the 'post' that .save! is called on is actually auto-generated by a method created by Decent Exposure. It returns a new record pre-populated with params[:post]... The failure I see is: Failure/Error: post :create, { :post => { :fake_param => "foobar" } } ActiveRecord::UnknownAttributeError: unknown attribute: foo # ./app/controllers/posts_controller.rb:107:in `new' ... So, I can't stub out "create!", because this failure is happening before there... And, if I do: Post.stubs(:new).returns(true) I still get the same failure. I even took it a step further where I explicitly told decent exposure to use a method: expose(:post) do exposed_for_post if params[:post] end def exposed_for_post Post.new(params[:post]) end .. And guess what? Doing subject.stubs(:exposed_for_post).returns true still gives me the same failure, unknown attribute: foo in 'new'... But, manually testing stuff proves that exposed_for_post method IS being called, and everything is working.. I just want an automated test to prove it. I am totally stumped on this one... Patrick J. Collins http://collinatorstudios.com
on 2011-11-20 06:58
On Nov 19, 2011, at 4:03 PM, Patrick J. Collins wrote: > individual methods. > > Failure/Error: post :create, { :post => { :fake_param => "foobar" } } > I even took it a step further where I explicitly told decent exposure to use a > .. And guess what? Doing subject.stubs(:exposed_for_post).returns true > rspec-users mailing list > rspec-users@rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users Please post the backtrace.
on 2011-11-20 08:52
> Please post the backtrace. Failures: 1) PostsController#store_post_params stores the last post params in the session Failure/Error: post :create, { :submit_action => submit_type.to_s, :post => { :foo => "bar" } } ActiveRecord::UnknownAttributeError: unknown attribute: foo # ./app/controllers/posts_controller.rb:107:in `new' # ./app/controllers/posts_controller.rb:107:in `exposed_for_session' # ./app/controllers/posts_controller.rb:9 # ./app/controllers/posts_controller.rb:37:in `create' # ./spec/controllers/post_spec.rb:6:in `do_post' # ./spec/controllers/post_spec.rb:25 ------------- and exposed_for_session is: def exposed_for_session Post.new(session.delete(:last_post_params)) if session[:last_post_params] end Like I said, I tried stubbing out the new class method on post by doing something like: fake_post = stub('Post', :save => true) Post.stubs(:new).returns(fake_post) But I still get that same failure. Patrick J. Collins http://collinatorstudios.com
on 2011-11-20 09:39
On Nov 19, 2011, at 11:14 PM, Patrick J. Collins wrote: > # ./app/controllers/posts_controller.rb:9 > end > _______________________________________________ > rspec-users mailing list > rspec-users@rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users I haven't used ActiveRecord in quite awhile (been using MongoDB), but it looks like you cannot instantiate a record with attributes that don't exist. I think you have two options here: 1.) Only use valid attributes in your params. 2.) Add `with` to your stub to exactly match the arguments to `.new`: Post.stubs(:new).with({last_post_params: {foo: 'bar'}}).returns(fake_post)
on 2011-11-20 10:01
> I haven't used ActiveRecord in quite awhile (been using MongoDB), but it looks like you cannot instantiate a record with attributes that don't exist. I think you have two options here: > > 1.) Only use valid attributes in your params. > 2.) Add `with` to your stub to exactly match the arguments to `.new`: > Post.stubs(:new).with({last_post_params: {foo: 'bar'}}).returns(fake_post) Yeah.. I originally had tried your 2nd option... Putting an expectation on the arguments sent to new made no difference. I just tried it again to verify, and I still get the same error. Seems so weird to me. Patrick J. Collins http://collinatorstudios.com
on 2011-11-20 13:57
On Nov 20, 2011, at 2:46 AM, Patrick J. Collins wrote: >> I haven't used ActiveRecord in quite awhile (been using MongoDB), but it looks like you cannot instantiate a record with attributes that don't exist. I think you have two options here: >> >> 1.) Only use valid attributes in your params. >> 2.) Add `with` to your stub to exactly match the arguments to `.new`: >> Post.stubs(:new).with({last_post_params: {foo: 'bar'}}).returns(fake_post) > > Yeah.. I originally had tried your 2nd option... Putting an expectation on > the arguments sent to new made no difference. I just tried it again to verify, > and I still get the same error. Seems so weird to me. Then use the first! The potential problem is that the params change and you need to change them here, but you can alleviate that with a method like valid_attributes: describe PostsController do def valid_attributes { :title => "Isolating change" } end describe "#store_params" do it "saves the post params for later" do session[:post_params].should be_blank post :create, { :post => valid_attributes } session[:post_params].should eq(valid_attributes) end end end You could also use FactoryGirl.attributes_for(:post) if you're using that tool. Either way, this removes the need to figure out where to stub what on the model. If you're concerned about the DB call, you could still stub save! but using valid_attributes would get you past the validations that happen before save!. HTH, David
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.