Errore di prova del controller RSPEC Metodo indefinito per NIL: Nilclass
-
20-12-2019 - |
Domanda
Sono nuovo a Rspec e sto cercando di entrare in tutta la mentalità BDD, quindi sono piuttosto scatenato di questo errore. Ho un motore dei binari che sto cercando di testare. Ecco il controller del bollettino. Fondamentalmente prima di qualsiasi azione che voglio popolare l'elenco dei corsi.
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
.
Il controller dell'applicazione ha alcuni metodi che voglio eseguire su ciascuna richiesta. Sto usando Devise nell'app Host in modo da avere accesso al metodo corrente_User
class ApplicationController < ::ApplicationController
before_filter :get_user
...
def get_user
@user = current_user
end
...
end
.
Ed ecco la specifica che sto cercando di eseguire:
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 provo a eseguire le specifiche, ottengo l'errore:
NoMethodError: undefined method 'id' for nil:NilClass
.
Capisco che sto ottenendo questo perché @user non è definito quando viene chiamato nell'edificio del bollettino; Tuttavia pensavo che il blocco prima della specifica definirebbe la variabile @User dopo aver sfuggito il: Get_User Filter. Quando provo le fabbriche nella console, tutto sembra essere creato con le associazioni corrette (Bollettino -> Autore, Bollettino -> Corso, ecc.).
Non sono sicuro di cosa mi manca sul motivo per cui la variabile @user non viene trasportata al mio codice controller. Qualsiasi intuizione e / o buoni tutorial per RSPEC sarebbe molto apprezzata.
Soluzione
Immagino che tu abbia anche bisogno di stub current_user
e sarà sufficiente (non è necessario stub get_user
):
before { controller.stub(:current_user).and_return (@user = create(:user)) }
.
E immagino che la buona pratica sia lasciare l'utente (se ne hai bisogno più di una volta):
routes { MyEngine::Engine.routes }
let!(:user) { create(:user) }
before { controller.stub(:current_user).and_return user }
.
Se hai bisogno di un accesso ai metodi privati, puoi provare qualcosa del genere:
subject.send(:current_user=, user)
.
Potrebbe essere un controller
invece di subject
, non è sicuro di quale versione supporta.
Aggiornamento.In realtà, è davvero difficile testare metodi privati.Ho controllato che current_user
in devise
definisce come:
def current_#{mapping}
@current_#{mapping} ||= warden.authenticate(scope: :#{mapping})
end
.
Quindi, puoi provare a stub warden.authenticate
per restituire user
:
allow_any_instance_of(Warden).to receive(:authenticate).and_return(create(:user))
. Altri suggerimenti
PROGETTO DI STUB OUT I metodi che si potrebbero usare potrebbero usare sarà abbastanza difficile a meno che tu non capisca come funziona il problema.
Il modo consigliabile per testare è semplicemente firmare all'utente utilizzando l'aiuto del test di Devise secondo la loro documentazione: 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
.
In questo modo, non dovrai preoccuparti di ideare i metodi e lo sfregandolo.Concentrati a testare il tuo metodo.:)