views:

42

answers:

1

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 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 => "[email protected]",
  :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!

+1  A: 

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
Steve Ross
As a side note, it's possible that setting expectations would be more effective than testing equality. Testing equality opens a question of "what does == mean in this context?".
Steve Ross
Ah, so sorry! I am creating the user. I have a before(:each) block that sets up everything I need. Also, I found the problem. In my controller, I have a line that sets: @project.owner = current_user.... If I change that to @project.owner_id = current_user.id, everything works. Strange.
hahuang65