Testing a post to a controller's create action

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 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?

Hi,

On Sat, Nov 19, 2011 at 09:42, Patrick J. Collins
[email protected] 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

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 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 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
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users

Please post the backtrace.

#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 Nov 19, 2011, at 11:14 PM, Patrick J. Collins wrote:

# ./app/controllers/posts_controller.rb:9

end


rspec-users mailing list
[email protected]
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)

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

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 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