Rails mock_model returning TrueClass?
Trying to test a controller in Rspec. (Rails 2.3.8, Ruby 1.8.7, Rspec 1.3.1, Rspec-Rails 1.3.3)
I'm trying to post a create but I get this error message:
ActiveRecord::AssociationTypeMismatch in 'ProjectsController with appropriate parameters while logged in: should create project' User(#2171994580) expected, got TrueClass(#2148251900)
My test code is as follows:
def mock_user(stubs = {})
@user = mock_model(User, stubs)
end
def mock_project(stubs = {})
@project = mock_model(Project, stubs)
end
def mock_lifecycletype(stubs = {})
@lifecycletype = mock_model(Lifecycletype, stubs)
end
it "should create project" do
post :create, :project => { :name => "Mock Project",
:description => "Mock Description",
:owner => @user,
:lifecycletype => mock_lifecycletype({ :name => "Mock Lifecycle" }) }
assigns[:project].should == mock_project({ :name => "Mock Project",
:description => "Mock Description",
:owner => mock_user,
:lifecycletype => mock_lifecycletype({ :name => "Mock Lifecycle" })})
flash[:notice].should == "Project was successfully created."
end
The trouble comes when I try to do :owner => @user
in the code above. For some reason, it thinks that my @user is TrueClass
instead of a User
class开发者_StackOverflow object. Funny thing is, if I comment out the post :create
code, and I do a simple @user.class.should == User
, it works, meaning that @user is indeed a User
class object.
I've also tried
:owner => mock_user
:owner => mock_user({ :name => "User",
:email => "user@email.com",
:password => "password",
:password_confirmation => "password })
:owner => @current_user
Note @current_user is also mocked out as a user, which I tested (the same way, @current_user.class.should == User
) and also returns a TrueClass
when I try to set :owner.
Anybody have any clue why this is happening?
Thank you!
From what I can see, you are not creating your instance variable, @user
before referencing it in the post
statement. You would do well to create the instance variables prior to the post so the preconditions are immediately obvious. That way you could know whether @user
had been set.
I know some people prefer the one-line-of-code-is-better-because-i'm-smart method of writing stuff like this, but I've found being explicit and even repetitive is a really good idea, particularly in tests.
I'm adding the following code that I believe may express your intent better that what you have. In my code, I use mock expectations to "expect" a Project
is created with a particular set of parameters. I believe your code assumes that you can do an equality comparison between a newly-created mock Project and a different one created during execution of your controller. That may not be true because they are distinctly different objects.
In my code, if you have a problem with something evaluating to TrueClass or the like, you can use a line of code like user.should be_a(User)
to the example to make sure stuff is wired up correctly.
def mock_user(stubs = {})
mock_model(User, stubs)
end
def mock_project(stubs = {})
mock_model(Project, stubs)
end
def mock_lifecycletype(stubs = {})
mock_model(Lifecycletype, stubs)
end
it "should create project" do
user = mock_user
owner = user
lifecycletype = mock_lifecycletype({ :name => "Mock Lifecycle" })
# Not certain what your params to create are, but the argument to with
# is what the params are expected to be
Project.should_receive(:create).once.with({:user => user, :owner => owner, :lifecycletype => lifecycletype})
post :create, :project => { :name => "Mock Project",
:description => "Mock Description",
:owner => @user,
:lifecycletype => lifecycletype }
flash[:notice].should == "Project was successfully created."
end
精彩评论