我是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
应用程序控制器有一些我希望在每个请求上运行的方法。我在主机应用程序中使用设计,因此我可以访问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变量。当我在控制台中测试工厂时,一切似乎都是用适当的关联创建的(公告 - &gt;作者,公告 - &gt;课程等)。
我不确定我为什么没有将@user变量传递给我的控制器代码。任何有关rspec的见解和/或好的教程都将不胜感激。
答案 0 :(得分:3)
除非你了解Devise的工作原理,否则试图将Devise可能使用的方法排除在外会非常困难。
推荐的测试方法是根据文档使用Devise测试助手简单地登录用户: 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
通过这种方式,您不必关心Devise方法并将其存根。只需专注于测试自己的方法。 :)
答案 1 :(得分:1)
我猜你还需要存根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_user
中的devise
定义如下:
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))