在test中设置current_user

时间:2012-08-20 14:02:51

标签: ruby-on-rails ruby-on-rails-3 ruby-on-rails-3.2

我有一个看起来像这样的测试:

test "should get create" do
   current_user = FactoryGirl.build(:user, email: 'not_saved_email@example.com')
   assert_difference('Inquiry.count') do
     post :create, FactoryGirl.build(:inquiry)
    end
    assert_not_nil assigns(:inquiry)
    assert_response :redirect
end

那是在测试控制器的这一部分:

def create
    @inquiry = Inquiry.new(params[:inquiry])
    @inquiry.user_id = current_user.id
    if @inquiry.save
      flash[:success] = "Inquiry Saved"
      redirect_to root_path
    else
      render 'new'
    end
  end

和工厂:

FactoryGirl.define do

  factory :inquiry do
    product_id 2
    description 'I have a question about....'
  end
end

但我的测试中一直出现错误:

      1) Error:
test_should_get_create(InquiriesControllerTest):
RuntimeError: Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id

我做错了什么?我需要设置current_user,我相信我正在测试中,但显然,这不起作用。

2 个答案:

答案 0 :(得分:3)

您没有创建current_user。它仅在test块中初始化。 有两种不同的方法可以做到:

首先,使用设计测试助手。像这样的东西

let(:curr_user) { FactoryGirl.create(:user, ...attrs...) }
sign_in curr_user

devise doc

其次,您可以在控制器中存储current_user方法以进行测试env

controller.stub(current_user: FactroryGirl.create(:user, ...attrs...))

您应该使用FactoryGirld.create(...)而不是FactoryGirl.build(...),因为必须保留工厂对象。(保存在db中并且id属性不是nil)

答案 1 :(得分:1)

有几件事情浮现在脑海中:

FactoryGirl.build(:user, ...)返回未保存的用户实例。我建议使用Factory.create代替它,因为对于未保存的实例,没有id,并且没有办法(通常基于会话的)current_user getter从数据库加载它。如果您正在使用Devise,则应在创建后“登录”用户。这包括在DB中保存记录并将其引用到会话中。 See devise wiki

此外,将ActiveRecord对象传递给create这样的动作对我来说很奇怪:

post :create, FactoryGirl.build(:inquiry)

也许在游戏中有一些魔法可以识别你的意图,但我建议明确地说:

post :create, :inquiry => FactoryGirl.build(:inquiry).attributes

或者更好的是,它与工厂分离(测试代码中的DRY和美学原理与应用程序代码不同):

post :create, :inquiry => {product_id: '2', description: 'I have a question about....'}

这引用id = 2的产品,除非您的数据库没有FK参考约束,否则在操作触发之前,产品实例可能需要存在于DB中。