2017-04-07 1 views
0

Ich baue eine Spielzeug-Chat-Anwendung mit Rails 4.2.7, und schreibe Spezifikationen für meine Controller mit rspec 3.5. Meine erfordert, dass ein Benutzer angemeldet ist, um einen Chatraum zu erstellen, also habe ich ein Api::SessionsHelper Modul erstellt, um Sitzungen innerhalb der Spezifikation zu erstellen.Rails 4 rspec 3-Controller-Test: Sitzungshelfer-Modul funktioniert nicht für vorher (: alle), funktioniert für vorher (: jeder)

# app/helpers/api/sessions_helper.rb 
module Api::SessionsHelper 
    def current_user 
    User.find_by_session_token(session[:session_token]) 
    end 

    def create_session(user) 
    session[:session_token] = user.reset_session_token! 
    end 

    def destroy_session(user) 
    current_user.try(:reset_session_token!) 
    session[:session_token] = nil 
    end 
end 


# spec/controllers/api/chatrooms_controller_spec.rb 
require 'rails_helper' 
include Api::SessionsHelper 

RSpec.describe Api::ChatroomsController, type: :controller do 
    before(:all) do 
    DatabaseCleaner.clean 
    User.create!({username: "test_user", password: "asdfasdf"}) 
    end 

    user = User.find_by_username("test_user") 

    context "with valid params" do 
    done = false 

    # doesn't work if using a before(:all) hook 
    before(:each) do 
     until done do 
     create_session(user) 
     post :create, chatroom: { name: "chatroom 1" } 
     done = true 
     end 
    end 

    let(:chatroom) { Chatroom.find_by({name: "chatroom 1"}) } 
    let(:chatroom_member) { ChatroomMember.find_by({user_id: user.id, chatroom_id: chatroom.id}) } 

    it "responds with a successful status code" do 
     expect(response).to have_http_status(200) 
    end 

    it "creates a chatroom in the database" do 
     expect(chatroom).not_to eq(nil) 
    end 

    it "adds the chatroom creator to the ChatroomMember table" do 
     expect(chatroom_member).not_to eq(nil) 
    end 
    end 

end 

Ich bin mit einem before(:each) Haken mit einem boolean Variable done das Verhalten eines before(:all) Haken zu erreichen, die für eine einzelne Sitzung zu schaffen.

Wenn ich eine Verwendung vor (: all) Haken, erhalte ich die Fehlermeldung:

NoMethodError: undefined method `session' for nil:NilClass` 

Ich habe einen Debugger in der create_session Methode des Api :: SessionsHelper Modul self.class und in beiden Fällen zu prüfen, wenn ich before(:each) verwenden und wenn ich before(:all) verwenden, ist die Klasse:

RSpec::ExampleGroups::ApiChatroomsController::WithValidParams 

jedoch, wenn die before(:each) Haken verwenden, Sitzung ist {}, während im before(:all) Haken, sessi auf gibt die NoMethodError oben.

Weiß jemand, was diesen Fehler verursacht?

Antwort

0

Sie benötigen die Helfer im Testblock enthalten:

RSpec.describe Api::ChatroomsController, type: :controller do 
    include Api::SessionsHelper 
end 

Sie auch Vervielfältigung, indem gemeinsame spec Helfer in spec/rails_helper.rb

RSpec.configure do |config| 
    # ... 
    config.include Api::SessionsHelper, type: :controller 
end 

Dies auch vermeiden kann, ist, wo Sie die database_cleaner setzen sollten Konfig. Sie sollten verwenden, um zwischen jeder Spezifikation nicht nur vor allem zu reinigen, da dies zu Testbestellproblemen und Flattertests führen wird.

require 'capybara/rspec' 

#... 

RSpec.configure do |config| 

    config.include Api::SessionsHelper, type: :controller 
    config.use_transactional_fixtures = false 

    config.before(:suite) do 
    if config.use_transactional_fixtures? 
     raise(<<-MSG) 
     Delete line `config.use_transactional_fixtures = true` from rails_helper.rb 
     (or set it to false) to prevent uncommitted transactions being used in 
     JavaScript-dependent specs. 

     During testing, the app-under-test that the browser driver connects to 
     uses a different database connection to the database connection used by 
     the spec. The app's database connection would not be able to access 
     uncommitted transaction data setup over the spec's database connection. 
     MSG 
    end 
    DatabaseCleaner.clean_with(:truncation) 
    end 

    config.before(:each) do 
    DatabaseCleaner.strategy = :transaction 
    end 

    config.before(:each, type: :feature) do 
    # :rack_test driver's Rack app under test shares database connection 
    # with the specs, so continue to use transaction strategy for speed. 
    driver_shares_db_connection_with_specs = Capybara.current_driver == :rack_test 

    if !driver_shares_db_connection_with_specs 
     # Driver is probably for an external browser with an app 
     # under test that does *not* share a database connection with the 
     # specs, so use truncation strategy. 
     DatabaseCleaner.strategy = :truncation 
    end 
    end 

    config.before(:each) do 
    DatabaseCleaner.start 
    end 

    config.append_after(:each) do 
    DatabaseCleaner.clean 
    end 

end 
+0

Es gibt auch mehrere andere Themen wie sollten Sie lernen, wie Sie mit [ 'let'] (https://www.relishapp.com/rspec/rspec-core/v/2-5/docs/helper -methods/let-and-let) anstelle von ivar oder lexikalischen Variablen wie 'user = User.find_by_username (" test_user ")'. – max

+0

Ihre allgemeine Methodik ist ebenfalls falsch - Sie sollten die Setup- und Teardown-Phase ('before' und' after') verwenden, um die Schiefertafel zu bereinigen und dann jedes Beispiel einzeln einzurichten. Die Verwendung von 'before_all' zum Einrichten eines Zustands, der von allen Beispielen in einer Datei verwendet werden soll, ist ein sehr fehlerhafter Ansatz. – max

+0

Danke für das Feedback, ich bin ziemlich neu zu schreiben Spezifikationen. Ist "Capybara" notwendig, wenn meine Controller nur json rendern? Außerdem habe ich versucht, den 'include Api :: SessionsHelper' in den Testblock und in den rails helper zu verschieben, und beide Fälle geben mir immer noch den gleichen Fehler, wenn ich' create_session' in 'before (: all)' benutze Haken. – nequalszero

Verwandte Themen