2010-11-18 6 views
2

J'essaie de tester l'action create de mon contrôleur. J'utilise Devise pour l'authentification et j'ai utilisé la méthode before_filter pour limiter l'accès à l'action create aux utilisateurs connectés. Voici la partie pertinente de mon contrôleur.Test des contrôleurs dans Rails 3 avec Devise et RSpec

class RawDataSetsController < ApplicationController 
    before_filter :authenticate_user!, :except => [:show, :index, :download] 

    def create 
    @raw_data_set = current_user.raw_data_sets.build(params[:raw_data_set]) 
    if @raw_data_set.save 
     redirect_to @raw_data_set 
    else 
     render "new" 
    end 
    end 
end 

Dans mon cas de test, je souhaite m'assurer qu'un utilisateur connecté peut créer un RawDataSet. Je pense que je me suis moqué d'un utilisateur authentifié selon les instructions sur this blog.

require 'spec_helper' 
describe RawDataSetsController do 

    include Devise::TestHelpers 

    def mock_users(stubs={}) 
    @user ||= mock_model(User, stubs).as_null_object 
    end 

    def log_in_test_user 
    attr = { :username => "Foobar", :email => "[email protected]" } 
    #mock up an authentication in warden as per http://www.michaelharrison.ws/weblog/?p=349 
    request.env['warden'] = mock(Warden, :authenticate => mock_users(attr), 
             :authenticate! => mock_users(attr), 
             :authenticate? => mock_users(attr)) 
    end 

    before do 
    @rds = Factory(:raw_data_set) 
    end 

    describe "POST 'create'" do 

    before do 
     @attr = { 
     :organism_name => "Beef Jerky", 
     :mass_spec_type => "My Stomach", 
     } 
    end 

    describe "logged in user" do 
     it "should create a raw_data_set when the user is logged in" do 
     log_in_test_user 
     lambda do 
      post :create, :raw_data_set => @attr 
     end.should change(RawDataSet, :count).by(1) 
     end 
    end 
    end 
end 

L'exécution de ce cas de test provoque l'erreur suivante:

1) RawDataSetsController POST 'create' logged in user should create a raw_data_set when the user is logged in 
Failure/Error: post :create, :raw_data_set => @attr 
undefined method `user_url' for #<RawDataSetsController:0x0000010175af88> 
# ./app/controllers/raw_data_sets_controller.rb:7:in `create' 

Je suis déconcerté par cette erreur. Après plus d'inspection, @raw_data_set n'est pas une instance de la classe de modèle RawDataSet, mais un utilisateur? Voici ce qu'il ressemble quand je p @raw_data_set

#<User:0x807a06a4 @name="User_1002"> 

Que diable se passe? Qu'est-ce que je fais mal? Comment puis-je tester l'action create sur mon contrôleur avec un utilisateur authentifié?

Répondre

1

EDIT(tout à fait tort première tentative retirée)

Appel as_null_object dit essentiellement la maquette d'accepter tous les messages qui ne sont pas et juste retour ont écrasé soi. Ainsi, lorsque vous appelez

current_user.raw_data_sets.build(params[:raw_data_set])

qui normalement retourner une nouvelle RawDataSet associée à current_user, au lieu que vous obtenez current_user à nouveau.

Ainsi, lorsque vous essayez d'appeler redirect, en passant @raw_data_set, vous êtes en lui passant la maquette au lieu d'une instance RawDataSet, donc l'appel à errante user_url.

Je pense que la façon de gérer cela est juste d'utiliser un vrai utilisateur (ou une usine) et stub out les méthodes Devise sur elle. Ainsi, votre mock_users devient (par exemple):

def mock_users(stubs={}) 
    @user = User.create(stubs) 
    end 

Maintenant current_user fera réellement la construction et sauver par l'association. Les puristes vous diront de se moquer et de tout boutonner jusqu'à ce que vous soyez bleus dans le visage. Vis ça - tu as de meilleures choses à faire. :)

L'autre façon d'aborder cela est de tester que le message de construction est reçu sans vérifier si la sauvegarde a réussi. Vraisemblablement vos tests de modèle vérifieront que l'économie à travers l'association fonctionne - pourquoi tester encore dans le contrôleur?

+0

Le problème est que cette ligne du contrôleur: @raw_data_set = current_user.raw_data_sets.build (params [: raw_data_set]) retourne une instance de la classe User dans mon test, ce qui n'est pas du tout ce que je veux qu'il fasse. Ce devrait être une instance de la classe RawDataSet, et rediriger vers RawDataSets # show. – jergason

+0

Merci pour votre aide. Je suis toujours au courant de RSpec, donc c'était très utile. – jergason

0

Si vous avez besoin de faire quelque chose de spécifique, par exemple modifier le comportement de la connexion, vous pouvez hériter des contrôleurs de conception et les remplacer. vous pouvez suivre les instructions d'ici https://github.com/plataformatec/devise les contrôleurs de configuration.

Questions connexes