rspec teste do controlador de erro indefinido método para nil:NilClass
-
20-12-2019 - |
Pergunta
Eu sou novo para o Rspec e eu estou tentando entrar em todo o BDD mentalidade, então, eu estou muito confuso sobre esse erro.Eu tenho rails engine que eu estou tentando testar.Aqui é o boletim de controlador.Basicamente, antes de qualquer ação que eu precisava para preencher a lista de cursos.
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
O aplicativo controlador possui alguns métodos que eu quero executar em cada pedido.Eu estou usando conceber o aplicativo de host para eu ter acesso ao método current_user
class ApplicationController < ::ApplicationController
before_filter :get_user
...
def get_user
@user = current_user
end
...
end
E aqui é a especificação eu estou tentando executar:
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
Quando tento executar a especificação, recebo a mensagem de erro:
NoMethodError: undefined method 'id' for nil:NilClass
Eu entendo que estou conseguindo isso porque @usuário não está definido quando é chamado no boletim do edifício;no entanto, eu pensei que o antes de bloco na especificação define o @variável de usuário depois de arrancar fora o :get_user filtro.Quando faço o teste de fábricas no console, tudo parece ser criados com as associações adequadas (boletim -> autor, boletim de -curso>, etc.).
Eu não tenho certeza do que eu estou ausente por que a @variável de usuário não está sendo realizada para o meu controlador de código.Qualquer insight e/ou bons tutoriais para rspec seria muito apreciada.
Solução
Eu acho que Você também precisa de stub current_user
e ele vai ser o suficiente (não há necessidade de stub get_user
):
before { controller.stub(:current_user).and_return (@user = create(:user)) }
E eu acho que a boa prática é deixar o usuário (se você precisa de mais do que uma vez):
routes { MyEngine::Engine.routes }
let!(:user) { create(:user) }
before { controller.stub(:current_user).and_return user }
Se você precisa de um acesso para métodos privados, você pode tentar algo como isto:
subject.send(:current_user=, user)
Poderia ser um controller
em vez de subject
, não tem certeza de qual a versão que suporta.
Atualização.Na verdade, é realmente complicado para testar métodos privados.Eu verifiquei que current_user
no devise
define como:
def current_#{mapping}
@current_#{mapping} ||= warden.authenticate(scope: :#{mapping})
end
Assim, você pode tentar de stub warden.authenticate
para retorna user
:
allow_any_instance_of(Warden).to receive(:authenticate).and_return(create(:user))
Outras dicas
Tentando simular os métodos que Maquinam poderia estar usando vai ser muito difícil, a menos que você compreender como Elaborar trabalhos.
A recomendação maneira de testar é a de simplesmente entrar o usuário usando a Conceber o teste de auxiliar, conforme a sua documentação: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
Desta forma, você não terá que se preocupar em criar métodos e arrancar-lo.Concentre-se apenas no teste de seu próprio método.:)