2012-04-12 19 views
39

He estado jugando con Rails durante un par de años y he producido un par de aplicaciones aceptables que están en producción. Sin embargo, siempre evité hacer pruebas y he decidido rectificar eso. Intento escribir algunas pruebas para una aplicación que escribí para el trabajo que ya está en funcionamiento pero en constante revisión. Me preocupa que cualquier cambio rompa las cosas, así que quiero ponerme a prueba y ponerme en funcionamiento. He leído el libro de RSpec, he visto algunas grabaciones de pantalla, pero estoy luchando por comenzar (me parece que es algo que solo entiendes una vez que lo has hecho).¿Cómo simulo un inicio de sesión con RSpec?

Estoy tratando de escribir lo que debería ser una simple prueba de ReportsController. El problema con mi aplicación es que prácticamente todo se encuentra detrás de una capa de autenticación. Nada funciona si no has iniciado sesión, así que tengo que simular un inicio de sesión antes de poder enviar una solicitud de obtención simple (aunque supongo que debería escribir algunas pruebas para asegurarme de que nada funciona sin un inicio de sesión; llegaré a eso más tarde).

He creado un entorno de prueba con RSpec, Capybara, FactoryGirl y Guard (no estaba seguro de qué herramientas usar, por lo tanto, las sugerencias de Railscasts). La forma en que escribí mi prueba hasta ahora es crear un usuario en FactoryGirl como tal;

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 

y luego escriba mi prueba como tal;

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 

Esto no funciona así;

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)>' 

Curiosamente si cambio de prueba para response.should be_redirect, se supera la prueba, que me hace pensar que todo está funcionando hasta ese momento, pero no se está reconociendo el inicio de sesión.

Así que mi pregunta es qué tengo que hacer para que este inicio de sesión funcione. ¿Necesito crear un usuario en la base de datos que coincida con las credenciales de FactoryGirl? Si es así, ¿cuál es el sentido de FactoryGirl aquí (y debería incluso usarlo)? ¿Cómo hago para crear este usuario falso en el entorno de prueba? Mi sistema de autenticación es uno muy simple hecho a sí mismo (basado en Railscasts episode 250). Probablemente, este comportamiento de inicio de sesión tendrá que replicarse para casi todas mis pruebas, entonces, ¿cómo hago para hacerlo una vez en mi código y que se aplique en todas partes?

Me doy cuenta de que esta es una gran pregunta, así que gracias por echar un vistazo.

Respuesta

36

La respuesta depende de la implementación de su autenticación. Normalmente, cuando un usuario inicia sesión, configurará una variable de sesión para recordar a ese usuario, algo así como session[:user_id]. Sus controladores comprobarán si hay un inicio de sesión en before_filter y lo redireccionarán si no existe dicha variable de sesión. Supongo que ya estás haciendo algo como esto.

Para que esto funcione en sus pruebas, debe insertar manualmente la información del usuario en la sesión. Aquí es parte de lo que usamos en el trabajo:

# 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 

Ahora en cualquiera de nuestros ejemplos controlador, podemos llamar login(some_user) para simular una sesión como ese usuario.


Debo mencionar también que parece que está haciendo pruebas de integración en esta prueba de controlador.Por regla general, las pruebas del controlador sólo se deben simulando las solicitudes a las acciones del controlador individuales, como:

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

Esto pone a prueba específicamente una sola acción del controlador, que es lo que desea en un conjunto de pruebas del controlador. Luego puede usar Capybara/Cucumber para pruebas de integración de formularios, vistas y controladores de extremo a extremo.

+1

Muy bien, gracias. Eso es un gran empujón en la dirección correcta. Lo puse en práctica y sigo teniendo una prueba fallida porque no tengo usuarios configurados en el entorno de prueba. ¿Cómo debo configurarlo? Use FactoryGirl? ¿Crearlos en la consola con un entorno de prueba? ¿Copia en una base de datos de producción existente al entorno de prueba? – brad

+0

En realidad, no te preocupes. Logré hacerlo con FactoryGirl como tal; 'describe" GET 'index' "do; "debería ser exitoso"; usuario = FactoryGirl.create (: usuario); inicio de sesión (usuario); obtener: índice; response.should be_success; final; final; '. Tuve que cambiar 'request.session [: user]' por 'request.session [: user_id]' pero, aparte de eso, todo en tu código me funcionaba y ahora tengo mi primera prueba de aprobación. Gracias. – brad

+0

Sí, su solución con FactoryGirl para crear el usuario es esencialmente lo que hacemos también. Por favor, asegúrese de aceptar la respuesta si funciona para usted. ¡Gracias! – Brandan

1

Como no pude hacer el trabajo @ respuesta de Brandan, pero en base a la misma y sobre this post, he llegó a esta solución:

# 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 

Y

# 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 

Luego, en sus pruebas puede utilizar: archivo

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

Agregar ayudante en spec/support/controlle r_helpers.rb y copiar el contenido a continuación

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 

Ahora añadir siguientes líneas en spec/rails_helper.rb o spec/spec_helper.rb archivo

require 'support/controller_helpers' 

RSpec.configure do |config| 

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

    end 

En su archivo de especificaciones del controlador .

describe "GET #index" do 

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

Devise Official Link

+0

No sé por qué tu respuesta obtuvo '-1' porque ese es el ÚNICO que realmente funcionó para mí, incluso parece un poco" desordenado "; muchas gracias hombre;) – Laurent

+0

gracias @Laurent. Me alegra que haya ayudado. (y) –

+0

En primer lugar, 'método indefinido create'. Si se supone que la persona debe cambiar 'create' a otra cosa, ¿por qué no lo menciona? ¿Debo reemplazar también 'describe' o' sign_in' a algo más? este pseudo-código es confuso. –

0

La forma más fácil de iniciar sesión con un usuario en las pruebas de función es el uso del Guardián helper #login_as

login_as some_user 
Cuestiones relacionadas