2010-11-18 124 views
2

我试图测试我的控制器的create操作。我正在使用Devise进行身份验证,并使用before_filter方法限制对登录用户访问create操作。这是我的控制器的相关部分。Rails 3中使用Devise和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 

在我的测试案例中,我想确保登录的用户可以创建一个RawDataSet。我认为我已经根据this博客帖子上的说明嘲笑了经过验证的用户。

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 

运行这个测试案例导致以下错误:

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' 

我对这个错误感到困惑。经过更多检查,@raw_data_set不是RawDataSet模型类的实例,而是用户?这就是当我p @raw_data_set

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

魔鬼正在发生什么?我究竟做错了什么?如何使用经过验证的用户在我的控制器上测试创建操作?

回答

1

编辑(完全错误的第一删除尝试)

调用as_null_object主要用来告诉模拟接受没有存根的所有消息,就回到自己。所以,当你调用

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

这通常会返回关联到current_userRawDataSet,而不是你爬不起来current_user

因此,当您尝试呼叫重定向,传递@raw_data_set时,您将它传递给模拟而不是RawDataSet实例,因此错误地调用user_url

我认为处理这个问题的方法只是使用一个真正的用户(或工厂),并在其上设计出Devise方法。所以,你的mock_users成为(例如):

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

现在current_user会怎么做构建,并通过关联保存。

纯粹主义者会告诉你嘲笑和剔除一切,直到你在脸上变得蓝色。拧紧 - 你有更好的事情要做。 :)

解决此问题的另一种方法是测试是否收到构建消息,而不检查保存是否成功。假设你的模型测试将验证通过该关联节省的工作 - 为什么再次在控制器中测试?

+0

问题是,来自控制器的这一行:@raw_data_set = current_user.raw_data_sets。build(params [:raw_data_set])正在我的测试中返回一个User类的实例,这完全不是我想要的。它应该是RawDataSet类的一个实例,并重定向到RawDataSets#show。 – jergason 2010-11-18 21:27:59

+0

谢谢你的帮助。我仍然得到RSpec的支持,所以这非常有帮助。 – jergason 2010-11-20 06:14:10