I've recently just added Devise to my first Rails3 app, and I'm having a bit of trouble with the controller tests.
I'm testing the User controller class, which is the same model that Devise uses. So at the beginning of my spec I have this:
before(:each) do
sign_in @user = Factory.create(:user)
end
Now I can get the test passing without using mocking or stubbing like so:
describe "GET edit" do
it "assigns the requested user as @user" do
user = Factory(:user)
get :edit, :id => user.id
assigns(:user).should eql(user)
end
end
But for educational purposes I would like to know how to get it to work with mocking and stubbing, normally it would be completely straight forward, but it seems Devise is calling User.find
before the controller action, and making the test fail.
describe "GET edit" do
it "assigns the requested user as @user" do
user = Factory(:user)
User.expects(:find).with(:first, :conditions => {:id => 37}).returns(user)
get :edit, :id => '37'
assigns(:user).should be(user)
end
end
Also by adding twice
onto the expectation this would also fail because the first call to find is different to the one I'm setting the expectation for.
Any insight would be appreciated.
You can specify multiple return values with either stubs
or expects
like so:
require 'test/unit'
require 'mocha'
class Foo
end
class FooTest < Test::Unit::TestCase
# This passes!
def test_multiple_returns_with_stubs
Foo.stubs(:find).returns('a').returns('b').returns('c')
assert_equal('a', Foo.find('z'))
assert_equal('b', Foo.find('y'))
assert_equal('c', Foo.find('x'))
end
# This passes too!
def test_multiple_returns_with_expects
Foo.expects(:find).times(1..3).returns('a').returns('b').returns('c')
assert_equal('a', Foo.find('z'))
assert_equal('b', Foo.find('y'))
assert_equal('c', Foo.find('x'))
end
end
The difference, apparently, is that expects
needs to know how many times it's going to be called. If you don't specify anything, it assumes once
and will complain on the subsequent calls. stubs
doesn't care.