Rails, Restful Authentication e RSpec: come testare nuovi modelli che richiedono l'autenticazione
-
09-06-2019 - |
Domanda
Ho creato un'applicazione di apprendimento utilizzando Bort, che è un'app di base che include l'autenticazione riposante e RSpec.L'ho installato e funzionante e ho aggiunto un nuovo oggetto che richiede che gli utenti abbiano effettuato l'accesso prima di poter fare qualsiasi cosa (before_filter :login_required
nel controllore).[modificare:Dovrei anche menzionare che il file user has_many
della nuova classe e solo l'utente dovrebbe essere in grado di vederla.]
Ho creato il nuovo modello/controller utilizzando i generatori di Rspec che hanno creato una serie di test predefiniti.Passano tutti se non c'è before_filter
ma molti falliscono, come prevedibile, una volta terminato before_filter
è a posto.
Come posso eseguire i test generati come se ci fosse/non fosse un utente connesso?Ho bisogno di un intero batch di test di reindirizzamento di corrispondenza non registrati?Presumo che sia una sorta di tecnica beffarda o di fissaggio, ma sono nuovo in RSpec e un po' alla deriva.Sarebbero apprezzati anche buoni collegamenti tutorial RSpec.
Soluzione
Ho una configurazione molto simile e di seguito è riportato il codice che sto attualmente utilizzando per testare queste cose.In ciascuno dei describe
s ho inserito:
it_should_behave_like "login-required object"
def attempt_access; do_post; end
Se tutto ciò di cui hai bisogno è un login, o
it_should_behave_like "ownership-required object"
def login_as_object_owner; login_as @product.user; end
def attempt_access; do_put; end
def successful_ownership_access
response.should redirect_to(product_url(@product))
end
Se hai bisogno di proprietà.Ovviamente, i metodi di aiuto cambiano (molto poco) ad ogni turno, ma questo fa la maggior parte del lavoro per te.Questo è nel mio spec_helper.rb
shared_examples_for "login-required object" do
it "should not be able to access this without logging in" do
attempt_access
response.should_not be_success
respond_to do |format|
format.html { redirect_to(login_url) }
format.xml { response.status_code.should == 401 }
end
end
end
shared_examples_for "ownership-required object" do
it_should_behave_like "login-required object"
it "should not be able to access this without owning it" do
attempt_access
response.should_not be_success
respond_to do |format|
format.html { response.should be_redirect }
format.xml { response.status_code.should == 401 }
end
end
it "should be able to access this if you own it" do
login_as_object_owner
attempt_access
if respond_to?(:successful_ownership_access)
successful_ownership_access
else
response.should be_success
end
end
end
Altri suggerimenti
Quando non testo l'autenticazione ma testo i controller che richiedono l'autenticazione dell'utente, di solito utilizzo il metodo di filtro:
before(:each) do
controller.stub!(:authenticate).and_return(true)
end
L'esempio sopra funziona dove il mio before_filter è impostato sul metodo di autenticazione:
before_filter :authenticate
e l'autenticazione nella mia app utilizza l'autenticazione di base HTTP, ma in realtà può essere qualsiasi altro meccanismo di autenticazione.
private
def authenticate
authenticate_or_request_with_http_basic do |user,password|
user == USER_NAME && password == PASSWORD
end
end
Penso che sia un modo abbastanza semplice per testare.
Ho trovato alcune risposte alla mia domanda.Fondamentalmente, avevo bisogno di capire come prendere in giro l'utente da restful_authentication
in modo che i test del controller rspec generati automaticamente potessero passare anche se avevo aggiunto before_filter: login_required
.
Ecco alcune delle risorse appena trovate:
Specifiche RS:Dovrebbe comportarsi come
rspec, restful_authentication e login_required
utilizzando restful_authentication current_user all'interno delle specifiche del controller
Per deridere un utente che ha effettuato l'accesso, hackero il controller per set @current_user
manualmente:
module AuthHelper
protected
def login_as(model, id_or_attributes = {})
attributes = id_or_attributes.is_a?(Fixnum) ? {:id => id} : id_or_attributes
@current_user = stub_model(model, attributes)
target = controller rescue template
target.instance_variable_set '@current_user', @current_user
if block_given?
yield
target.instance_variable_set '@current_user', nil
end
return @current_user
end
def login_as_user(id_or_attributes = {}, &block)
login_as(User, id_or_attributes, &block)
end
end