Rails mock_model返回TrueClass?

时间:2010-10-24 03:32:45

标签: ruby-on-rails mocking rspec functional-testing

尝试在Rspec中测试控制器。 (Rails 2.3.8,Ruby 1.8.7,Rspec 1.3.1,Rspec-Rails 1.3.3)

我正在尝试发布创建,但收到此错误消息:

登录时具有适当参数的'ProjectsController中的 ActiveRecord :: AssociationTypeMismatch:应该创建项目'     用户(#2171994580)预期,获得TrueClass(#2148251900)

我的测试代码如下:

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

当我尝试在上面的代码中执行:owner => @user时出现问题。出于某种原因,它认为我的@user是TrueClass而不是User类对象。有趣的是,如果我注释掉post :create代码,并且我做了一个简单的@user.class.should == User,它就可以了,这意味着@user确实是一个User类对象。

我也试过

:owner => mock_user
:owner => mock_user({ :name => "User",
  :email => "user@email.com",
  :password => "password",
  :password_confirmation => "password })
:owner => @current_user

注意@current_user也被模拟为用户,我测试了它(同样的方式,@current_user.class.should == User),并在我尝试设置:owner时返回TrueClass

任何人都知道为什么会发生这种情况?

谢谢!

1 个答案:

答案 0 :(得分:1)

从我所看到的情况来看,您并未在@user语句中引用它之前创建实例变量post。你最好在帖子之前创建实例变量,这样前提条件就会很明显。这样你就可以知道是否设置了@user

我知道有些人更喜欢单行代码 - 更好 - 因为我很聪明的方法写这样的东西,但我发现是明确的,甚至重复是一个非常好的主意,特别是在测试中。

我正在添加以下代码,我相信这些代码可以更好地表达您的意图。在我的代码中,我使用模拟期望“期望”使用一组特定参数创建Project。我相信您的代码假定您可以在新创建的模拟项目和在执行控制器期间创建的不同项目之间进行相等比较。这可能不是真的,因为它们是明显不同的对象。

在我的代码中,如果您对使用TrueClass等进行评估时遇到问题,可以在示例中使用一行代码user.should be_a(User)来确保连接正确。

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