RSpec-Controller-Testfehler, undefinierte Methode für nil:NilClass
-
20-12-2019 - |
Frage
Ich bin neu bei Rspec und versuche, mich mit der gesamten BDD-Denkweise vertraut zu machen, daher bin ich über diesen Fehler ziemlich ratlos.Ich habe eine Rails-Engine, die ich testen möchte.Hier ist der Bulletin-Controller.Grundsätzlich möchte ich vor jeder Aktion die Liste der Kurse füllen.
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
Der Anwendungscontroller verfügt über einige Methoden, die ich bei jeder Anfrage ausführen möchte.Ich verwende „devise“ in der Host-App, sodass ich Zugriff auf die Methode „current_user“ habe
class ApplicationController < ::ApplicationController
before_filter :get_user
...
def get_user
@user = current_user
end
...
end
Und hier ist die Spezifikation, die ich ausführen möchte:
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
Wenn ich versuche, die Spezifikation auszuführen, erhalte ich die Fehlermeldung:
NoMethodError: undefined method 'id' for nil:NilClass
Ich verstehe, dass ich das bekomme, weil @user nicht definiert ist, wenn es im Bulletin-Building aufgerufen wird;Allerdings dachte ich, dass der Before-Block in der Spezifikation die @user-Variable definieren würde, nachdem der :get_user-Filter gelöscht wurde.Wenn ich die Fabriken in der Konsole teste, scheint alles mit den richtigen Zuordnungen erstellt zu sein (Bulletin -> Autor, Bulletin -> Kurs usw.).
Ich bin mir nicht sicher, was mir fehlt und warum die @user-Variable nicht in meinen Controller-Code übernommen wird.Für Einblicke und/oder gute Tutorials zu rspec wäre ich sehr dankbar.
Lösung
Ich denke, Sie müssen auch stummeln current_user
und es wird ausreichen (keine Notwendigkeit zu stummeln get_user
):
before { controller.stub(:current_user).and_return (@user = create(:user)) }
Und ich denke, die gute Vorgehensweise besteht darin, dem Benutzer zu erlauben (wenn Sie ihn mehr als einmal benötigen):
routes { MyEngine::Engine.routes }
let!(:user) { create(:user) }
before { controller.stub(:current_user).and_return user }
Wenn Sie Zugriff auf private Methoden benötigen, können Sie Folgendes versuchen:
subject.send(:current_user=, user)
Könnte ein sein controller
anstatt subject
, nicht sicher, welche Version unterstützt wird.
Aktualisieren.Eigentlich ist es wirklich schwierig, private Methoden zu testen.Ich habe das überprüft current_user
In devise
definiert wie:
def current_#{mapping}
@current_#{mapping} ||= warden.authenticate(scope: :#{mapping})
end
Sie können also Stub ausprobieren warden.authenticate
zur Rückgabe user
:
allow_any_instance_of(Warden).to receive(:authenticate).and_return(create(:user))
Andere Tipps
Versuch, die Methoden zu stumm herausstufen, die verwendet werden könnten, ist ziemlich schwierig, es sei denn, Sie verstehen, wie erarbeiten Arbeiten.
Der Empfehlungsweg, um zu testen, besteht darin, den Benutzer einfach mit einem Defise-Testhelfer gemäß deren Dokumentation anzumelden: https://github.com/plataFormatec/devise#Test-Helpers
generasacodicetagpre.Auf diese Weise müssen Sie sich nicht darum kümmern, um Methoden zu entwickeln und zu stummeln.Fokussieren Sie einfach auf das Testen Ihrer eigenen Methode.:)