【问题标题】:Testing create action in polymorphic comments controller Rspec - undefined method `comments' for nil:NilClass在多态注释控制器 Rspec 中测试创建操作 - nil:NilClass 的未定义方法“注释”
【发布时间】:2013-06-29 14:38:56
【问题描述】:

我正在尝试在我的多态 cmets 控制器中测试 POST 创建操作。运行下面的规范时,它们会因错误而失败:

undefined method `comments' for nil:NilClass

我认为这意味着 @commentable 没有被正确创建/设置,所以它不存在。 ATM 我正在​​删除 load_commentable 方法并返回 FactoryGirl 问题对象,但这似乎仍然没有解决任何问题。

如何修改我的规范,以便正确创建可评论对象,并在 @commentable 范围内创建评论,就像在实际控制器中一样?

cmets_controller.rb

def create 
    @comment = @commentable.comments.build(params[:comment])
    @comment.user_id = current_user.id
    respond_to do |format|
    if @comment.save
        format.html { redirect_to @commentable, notice: 'Comment created'}
        format.js
    else
      format.html { redirect_to @commentable, notice: "Content can't be blank" }
      format.js
      end
    end
  end

def load_commentable
    resource, id = request.path.split('/')[1,2]
    @commentable = resource.singularize.classify.constantize.find(id)
  end

cmets_controller_spec.rb

describe CommentsController do
  include Devise::TestHelpers
  include AnswerHelper
  before(:each) do
    @user = create(:user)
    @user2 = create(:user)
    sign_in @user
    sign_in @user2
    @commentable = create(:question, user: @user2)
    @comment = create(:comment, user: @user)
    @vote = attributes_for(:vote, user: @user2, votable_id: @commentable)
    controller.stub!(:load_commentable).and_return(@commentable)
    controller.stub!(:current_user).and_return(@user)
    @request.env['HTTP_REFERER'] = "http://test.host/questions/#{@commentable.id}"
    stub_model_methods
  end

  describe "POST create" do
    describe "with valid params" do
      it "creates a new comment" do
        expect {
          post :create, comment: attributes_for(:comment), commentable: @commentable
        }.to change(Comment, :count).by(1)
      end

      it "assigns a newly created comment as @comment" do
        post :create, comment: attributes_for(:comment), commentable: @commentable
        assigns(:comment).should be_a(Comment)
        assigns(:comment).should be_persisted
      end
    end

    describe "with invalid params" do
      it "assigns a newly created but unsaved comment as @comment" do
        Comment.any_instance.stub(:save).and_return(false)
        post :create, comment: attributes_for(:comment), commentable: @commentable
        assigns(:comment).should be_a_new(Comment)
      end
    end
  end

工厂.rb

factory :comment do
    user
    commentable_id :question
    commentable_type "Question"
    content "a comment"
    votes_count 5
  end

rspec 结果

1) CommentsController POST create with valid params creates a new comment
     Failure/Error: post :create, comment: attributes_for(:comment), commentable: @commentable
     NoMethodError:
       undefined method `comments' for nil:NilClass
     # ./app/controllers/comments_controller.rb:19:in `create'
     # ./spec/controllers/comments_controller_spec.rb:24:in `block (5 levels) in <top (required)>'
     # ./spec/controllers/comments_controller_spec.rb:23:in `block (4 levels) in <top (required)>'

【问题讨论】:

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


    【解决方案1】:

    这里的问题是您正在删除 load_commentable,它负责在您的控制器中设置实例变量 @commentable。由于您正在对它进行存根,它永远不会被调用,并且 ivar 永远不会被设置 - 您不能直接从 rspec 测试套件在控制器中设置 ivars。

    由于您正在创建记录,因此您实际上不需要存根任何内容,只需传递@commentable.id,然后从数据库中查找它即可。但是,如果您出于某种原因想避免查找,则可以使用:

    Question.stub(:find).with(@commentable.id).and_return(@commentable)
    

    这将导致您的控制器使用您的@commentable 对象,并将其分配给控制器中的@commentable,此时测试应继续正常运行。

    【讨论】:

    • 嗨,克里斯,这确实有道理,但是将 commentable.id 传递给评论属性哈希会使测试文件出现:找不到没有 ID 的评论。
    • 你的测试通过了@commentable,而不是@commentable.id
    猜你喜欢
    • 2011-10-23
    • 2013-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-19
    相关资源
    最近更新 更多