Patrick J. Collins
2011-Dec-02 00:34 UTC
[rspec-users] problem setting expectation for test with delayed::job
I''ve got something like this: # post_observer.rb after_create # ...stuff Delayed::Job.enqueue(PostSharer.new(post, post.user)) end ... # post_sharer.rb class PostSharer < Struct.new(:post, user) def perform # Delayed::Job calls .perform on the object passed into enqueue end end # post_controller_spec.rb it "shares the post" do PostSharer.expects(:new).once lambda { do_post }.should change(Delayed::Job, :count).by(1) end ... This fails due to the expectation put on PostSharer receiving .new --- if I remove that, then it all works fine... And if I look at the test database, Delayed::Job has created a job for PostSharer, so it is all working as desired.. I just wanted to take it a step further and ensure that the right class is being instantiated. I am assuming this is because setting an expectation on new is somehow changing the structure of the class and confusing delayed job? Maybe because it''s a struct? 1) PostsController creating a post sharing shares when it should Failure/Error: post :create, { :submit_action => submit_type.to_s, :post => new_post(post_attributes).attributes } ArgumentError: Cannot enqueue items which do not respond to perform # ./app/observers/post_observer.rb:12:in `after_create'' # ./app/models/post.rb:156:in `set_state_to_open_for_free_requests'' # ./app/controllers/posts_controller.rb:39:in `create'' # ./spec/controllers/post_controller_spec.rb:8:in `do_post'' # ./spec/controllers/post_controller_spec.rb:77 # ./spec/controllers/post_controller_spec.rb:75 Patrick J. Collins http://collinatorstudios.com
David Chelimsky
2011-Dec-02 04:43 UTC
[rspec-users] problem setting expectation for test with delayed::job
On Dec 1, 2011, at 6:34 PM, Patrick J. Collins wrote:> I''ve got something like this: > > # post_observer.rb > > after_create > # ...stuff > Delayed::Job.enqueue(PostSharer.new(post, post.user)) > end > > ... > > # post_sharer.rb > > class PostSharer < Struct.new(:post, user) > > def perform > # Delayed::Job calls .perform on the object passed into enqueue > end > > end > > # post_controller_spec.rb > > it "shares the post" do > > PostSharer.expects(:new).once > lambda { do_post }.should change(Delayed::Job, :count).by(1) > > end > > ... > > This fails due to the expectation put on PostSharer receiving .new --- if I > remove that, then it all works fine... And if I look at the test database, > Delayed::Job has created a job for PostSharer, so it is all working as > desired..You could automate "if I look at the test database" bit as part of the test.> I just wanted to take it a step further and ensure that the right > class is being instantiated.Wouldn''t the record in the database be enough? If not, you could do this: Delayed::Job.expects(:enqueue).with(PostSharer.new(post, post.user))> I am assuming this is because setting an > expectation on new is somehow changing the structure of the class and confusing > delayed job? Maybe because it''s a struct?In rspec-mocks, when you say Klass.stub(:new), Klass.new returns a proxy, not an instance of the Klass. I''m pretty sure the same is true of mocha. Cheers, David> 1) PostsController creating a post sharing shares when it should > Failure/Error: post :create, { :submit_action => submit_type.to_s, :post => new_post(post_attributes).attributes } > ArgumentError: > Cannot enqueue items which do not respond to perform > # ./app/observers/post_observer.rb:12:in `after_create'' > # ./app/models/post.rb:156:in `set_state_to_open_for_free_requests'' > # ./app/controllers/posts_controller.rb:39:in `create'' > # ./spec/controllers/post_controller_spec.rb:8:in `do_post'' > # ./spec/controllers/post_controller_spec.rb:77 > # ./spec/controllers/post_controller_spec.rb:75 > > Patrick J. Collins > http://collinatorstudios.com
Patrick J. Collins
2011-Dec-02 05:39 UTC
[rspec-users] problem setting expectation for test with delayed::job
> In rspec-mocks, when you say Klass.stub(:new), Klass.new returns a proxy, not > an instance of the Klass. I''m pretty sure the same is true of mocha.Ok-- I guess I wasn''t realizing that Klass.expects(:new) was actually stubbing the class.. I was thinking it was doing something like making a duplicate of the initialize method (making it something like "_initialize") and then overwriting the real initialize method with something that calls _initialize but also sets a flag to indicate that .new had been called... So that''s apparently not quite the case? In any event, after reading what you wrote I got my test to pass by doing: PostSharer.expects(:new).once.returns stub("Fake Post Sharer", :perform => true) So this way delayed_job still can call perform on the fake object and everyone is happy (especially me). Patrick J. Collins http://collinatorstudios.com