2012-04-12 12 views
39

Gram w Rails od kilku lat i wyprodukowałem kilka łatwych w użyciu aplikacji, które są w produkcji. Zawsze jednak unikałem jakichkolwiek testów i postanowiłem to naprawić. Próbuję napisać kilka testów dla aplikacji, którą napisałem do pracy, która jest już uruchomiona, ale przechodzi ciągłą weryfikację. Obawiam się, że wszelkie zmiany złamie, więc chcę, aby niektóre testy zostały uruchomione. Przeczytałem książkę RSpec, obejrzałem kilka screencastów, ale staram się zacząć (to uderza mnie jako coś, co rozumiesz tylko wtedy, gdy już to zrobiłeś).Jak zasymulować logowanie przy użyciu protokołu RSpec?

Próbuję napisać, co powinno być prostym testem mojego ReportsController. Problem z moją aplikacją polega na tym, że prawie wszystko znajduje się za warstwą uwierzytelniania. Nic nie działa, jeśli nie jesteś zalogowany, więc muszę zasymulować logowanie zanim będę mógł wysłać prostą prośbę o pobranie (chociaż domyślam się, że powinienem napisać kilka testów, aby upewnić się, że nic nie działa bez logowania - dostanę się do to później).

Skonfigurowałem środowisko testowe z RSpec, Capybara, FactoryGirl i Guard (nie byłem pewien, które narzędzia użyć tak użytych sugestii Railscasts). Sposób, w jaki pisałem o moim teście do tej pory, polega na stworzeniu użytkownika w FactoryGirl;

FactoryGirl.define do 
    sequence(:email) {|n| "user#{n}@example.com"} 
    sequence(:login) {|n| "user#{n}"} 
    factory :user do 
    email {FactoryGirl.generate :email} 
    login {FactoryGirl.generate :login} 
    password "abc" 
    admin false 
    first_name "Bob" 
    last_name "Bobson" 
    end 
end 

a następnie napisz mój test tak;

require 'spec_helper' 

describe ReportsController do 
    describe "GET 'index'" do 
    it "should be successful" do 
     user = Factory(:user) 
     visit login_path 
     fill_in "login", :with => user.login 
     fill_in "password", :with => user.password 
     click_button "Log in" 
     get 'index' 
     response.should be_success 
    end 
    end 
end 

To nie tak jak;

1) ReportsController GET 'index' should be successful 
    Failure/Error: response.should be_success 
     expected success? to return true, got false 
    # ./spec/controllers/reports_controller_spec.rb:13:in `block (3 levels) in <top (required)>' 

Co ciekawe, jeśli mogę zmienić test response.should be_redirect, test przechodzi co sugeruje mi się, że wszystko działa aż do tej chwili, ale logowanie nie jest rozpoznawane.

Moje pytanie brzmi, co muszę zrobić, aby to logowanie działało. Czy muszę utworzyć użytkownika w bazie danych, która pasuje do danych logowania FactoryGirl? Jeśli tak, jaki jest sens FactoryGirl tutaj (a powinienem nawet z niego korzystać)? Jak mam zrobić tego fałszywego użytkownika w środowisku testowym? Mój system uwierzytelniania jest bardzo prosty, samodzielnie wykonany (oparty na Railscasts episode 250). To zachowanie logowania będzie prawdopodobnie musiało być zreplikowane dla prawie wszystkich moich testów, więc jak mam zrobić to raz w moim kodzie i mając go wszędzie?

Zdaję sobie sprawę, że jest to duże pytanie, więc dziękuję za spojrzenie.

Odpowiedz

36

Odpowiedź zależy od implementacji uwierzytelniania. Normalnie, gdy użytkownik się loguje, ustawisz zmienną sesji, aby zapamiętać tego użytkownika, coś w rodzaju session[:user_id]. Twoi kontrolerzy będą sprawdzać logowanie pod numerem before_filter i przekierować, jeśli taka zmienna sesji nie istnieje. Zakładam, że już coś takiego robisz.

Aby to zadziałało podczas testów, należy ręcznie wprowadzić informacje o użytkowniku do sesji. Oto część tego, co używamy w pracy:

# spec/support/spec_test_helper.rb 
module SpecTestHelper 
    def login_admin 
    login(:admin) 
    end 

    def login(user) 
    user = User.where(:login => user.to_s).first if user.is_a?(Symbol) 
    request.session[:user] = user.id 
    end 

    def current_user 
    User.find(request.session[:user]) 
    end 
end 

# spec/spec_helper.rb 
RSpec.configure do |config| 
    config.include SpecTestHelper, :type => :controller 
end 

Teraz w każdym z naszych przykładów kontrolera, możemy wywołać login(some_user) symulować zalogowaniu się jako użytkownik.


Powinienem również wspomnieć, że wygląda na to, że przeprowadzacie test integracyjny w tym teście kontrolera.Co do zasady, swoje testy kontrolera należy symulując tylko wnioski do poszczególnych działań kontrolerów, takich jak:

it 'should be successful' do 
    get :index 
    response.should be_success 
end 

Ten specjalnie testuje jedną akcję kontrolera, który jest, co chcesz w zestawie testów regulatora. Następnie możesz użyć Capybara/Cucumber do kompleksowego testowania formularzy, widoków i kontrolerów.

+1

Wielki, dzięki. To ogromny krok w dobrym kierunku. Wprowadziłem to w życie i wciąż mam test na awarię, ponieważ nie mam żadnych użytkowników skonfigurowanych w środowisku testowym. Jak mam je skonfigurować? Użyj FactoryGirl? Utworzyć je w konsoli za pomocą środowiska testowego? Skopiować istniejącą produkcyjną bazę danych do środowiska testowego? – brad

+0

Właściwie, nie martw się. Udało mi się to zrobić za pomocą FactoryGirl; 'opisz" GET 'index' "do; "powinien odnieść sukces"; użytkownik = FactoryGirl.create (: użytkownik); logowanie (użytkownik); get: index; response.should be_success; koniec; koniec; '. Musiałem zmienić 'request.session [: user]' na 'request.session [: user_id]' ale poza tym wszystko w twoim kodzie działało dla mnie i teraz mam swój pierwszy test przejścia! Dziękuję Ci. – brad

+0

Tak, twoje rozwiązanie z FactoryGirl do stworzenia użytkownika jest w zasadzie tym, co robimy. Pamiętaj, aby zaakceptować odpowiedź, jeśli działa ona dla Ciebie. Dzięki! – Brandan

1

Ponieważ nie mogłem @ pracy odpowiedzi Brandan, ale opiera się na nim i na this post, ja przyszedł do tego rozwiązania:

# spec/support/rails_helper.rb 
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } # Add this at top of file 

... 

include ControllerMacros # Add at bottom of file 

I

# spec/support/controller_macros.rb 
module ControllerMacros 

    def login_as_admin 
    admin = FactoryGirl.create(:user_admin) 
    login_as(admin) 
    end 

    def login_as(user) 
    request.session[:user_id] = user.id 
    end 

end 

Następnie na wynikach badań można użyć:

it "works" do 
    login_as(FactoryGirl.create(:user)) 
    expect(request.session[:user_id]).not_to be_nil 
end 
7

Dodaj plik pomocnika w SPEC/support/controlle r_helpers.rb i kopiowanie zawartości poniżej

module ControllerHelpers 
    def sign_in(user) 
     if user.nil? 
     allow(request.env['warden']).to receive(:authenticate!).and_throw(:warden, {:scope => :user}) 
     allow(controller).to receive(:current_user).and_return(nil) 
     else 
     allow(request.env['warden']).to receive(:authenticate!).and_return(user) 
     allow(controller).to receive(:current_user).and_return(user) 
     end 
    end 
    end 

teraz dodać następujące wiersze w specyfikacji/rails_helper.rb lub SPEC/spec_helper.rb plik

require 'support/controller_helpers' 

RSpec.configure do |config| 

    config.include Devise::TestHelpers, :type => :controller 
    config.include ControllerHelpers, :type => :controller 

    end 

Teraz w pliku spec regulatora .

describe "GET #index" do 

    before :each do   
     @user=create(:user) 
     sign_in @user 
    end 
     ... 
end 

Devise Official Link

+0

Nie wiem, dlaczego twoja odpowiedź dostała "-1", ponieważ jest to TYLKO jedna, która faktycznie działała dla mnie, nawet wygląda trochę "niechlujnie"; bardzo dziękuję;) – Laurent

+0

dzięki @Laurent. Cieszę się, że pomogło. (y) –

+0

Przede wszystkim "niezdefiniowana metoda create". Jeśli dana osoba miała zmienić "tworzenie" na coś innego, to dlaczego by o tym nie wspomnieć? Czy powinienem też zastąpić "opisz" lub "sign_in" czymś innym? ten pseudo-kod jest mylący. –

0

Najprostszym sposobem, aby zalogować się z użytkownikiem w sprawie badań cechą jest użycie naczelnika helper #login_as

login_as some_user 
Powiązane problemy