RSpec Mocks Question for ActiveRecord Find First with Where
I am trying to sort out my RSpec tests for a controller of mine, but its not working and I need some help figuring it out.
My Rspec is:
before(:each) do
@topic = mock_model(Topic, :update_attributes => true)
Topic.stub!(:where).with({:slug=>"some-slug"}).and_return(@topic)
with_valid_user
end
it "should find topic and return object" do
Topic.should_receive(:where).with("some-slug").and_return(@topic)
put :update, :topic_slug => "some-slug", :topic => {}
end
The controller logic I am trying to test is:
def get_topic
@topic = Topic.where(:slug => params[:topic_slug]).first
@topic
end
But the output I am getting is:
Failure/Error: Topic.stub!(:where).with({:slug=>"some-slug"}).first.and_return(@topic)
NoMethodError:
undefined method `first' for #<RSpec::Mocks::MessageExpectation:0x104c99910>
# ./spec/c开发者_StackOverflow社区ontrollers/topics_controller_spec.rb:41
Obviously, it seems like the method call for "first". I understand is a bit redundant in this particular case, so I could remove it, but rather than hack around a hole in my knowledge, I'd like to learn how to do it properly (for this scenario).
Can anyone help me fill my hole?
Update:
I added the [@topic] array as suggested in the answers, but now I am getting the error:
Failure/Error: put :update, :topic_slug => "some-slug", :topic => {}
Mock "Topic_1001" received unexpected message :slug with (no args)
With respect to this code:
def get_topic
@topic = Topic.where(:slug => params[:topic_slug]).first
@topic
end
The parameters can't be changed (at least not trivially). Further assistance greatly appreciated!
Change this line
Topic.should_receive(:where).with("some-slug").and_return(@topic)
to this
Topic.should_receive(:where).with("some-slug").and_return([@topic])
you expect array but return one element.
stub_chain
is a code smell and should be treated as a last resort. It ties your spec very tightly to implementation detail, which is subject to change via refactoring.
I'd recommend something like this:
Topic.should_receive(:with_slug).and_return(@topic)
Then add a with_slug
method to Topic
and you're good to go.
精彩评论