我是 Rspec 的新手,我正在尝试进入整个 BDD 思维模式,所以我对这个错误感到非常困惑。我有正在尝试测试的 Rails 引擎。这是公告控制器。基本上,在执行任何操作之前,我想填充课程列表。

class BulletinsController < ApplicationController
  before_filter :get_courses

  def new
    @bulletin = Bulletin.new(author_id: @user.id)
  end

 ...

 private
 def get_courses
   if @user.has_role? :admin
     @course_list = Course.all.sort_by(&:start_date)
   ...
   end
 end

应用程序控制器有一些我想在每个请求上运行的方法。我在主机应用程序中使用 devise,因此我可以访问 current_user 方法

class ApplicationController < ::ApplicationController
  before_filter :get_user
  ...
  def get_user
    @user = current_user
  end
  ...
end

这是我试图运行的规范:

describe BulletinsController do
  routes { MyEngine::Engine.routes }
  before { controller.stub(:authenticate_user!).and_return true }
  before { controller.stub(:get_user).and_return (@user = create(:user)) }

  describe "GET #new" do
    it "assigns a new bulletin to @bulletin" do
      bulletin = create(:bulletin)
      controller.stub(:get_courses)
      get :new
      assigns(:bulletin).should eq(bulletin)
    end
  end 
end

当我尝试运行规范时,出现错误:

NoMethodError: undefined method 'id' for nil:NilClass

我知道我得到这个是因为在公告大楼中调用 @user 时未定义它;但是我认为规范中的 before 块会在删除 :get_user 过滤器后定义 @user 变量。当我在控制台中测试工厂时,所有内容似乎都是通过正确的关联创建的(公告 -> 作者、公告 -> 课程等)。

我不确定我缺少什么来解释为什么 @user 变量没有被传递到我的控制器代码中。任何有关 rspec 的见解和/或好的教程将不胜感激。

有帮助吗?

解决方案

我想你还需要存根 current_user 这就足够了(不需要存根 get_user):

before { controller.stub(:current_user).and_return (@user = create(:user)) }

我想最好的做法是让用户(如果您多次需要它):

routes { MyEngine::Engine.routes }
let!(:user) { create(:user) }
before { controller.stub(:current_user).and_return user }

如果您需要访问私有方法,您可以尝试如下操作:

subject.send(:current_user=, user)

可能是一个 controller 代替 subject, ,不知道支持什么版本。

更新。实际上,测试私有方法确实很棘手。我查了一下 current_userdevise 定义如下:

def current_#{mapping}
  @current_#{mapping} ||= warden.authenticate(scope: :#{mapping})
end

所以,你可以尝试存根 warden.authenticate 退货 user:

allow_any_instance_of(Warden).to receive(:authenticate).and_return(create(:user))

其他提示

试图存根设计的方法可以使用的是非常困难,除非您了解设计的设计方式。

推荐的测试方式是只需根据其文档使用Devise Test Helper即可登录用户: https://github.com/plataformatec/devise#test-helpers

describe BulletinsController do
  routes { MyEngine::Engine.routes }
  before { sign_in(user) }

  let!(:user) { create(:user) }

  describe "GET #new" do
    it "assigns a new bulletin to @bulletin" do
      bulletin = create(:bulletin)
      controller.stub(:get_courses)
      get :new
      assigns(:bulletin).should eq(bulletin)
    end
  end 
end
.

这样,您将不必关心设计方法并将其存入。只关注测试自己的方法。:)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top