Ruby on rails - Devise 在使用 FactoryGirl 的控制器测试中无法正确登录



在尝试让 Devise 在我的控制器测试中正确登录时,我有一些有趣的行为。它似乎在某些情况下有效,但在其他情况下无效。我不确定这是Devise和FactoryGirl之间的互动还是其他工作。

首先,这是我的工厂:

factory :advisor do
  name "Jason Jones"
  association :user
  initialize_with {Advisor.find_or_create_by_name('Jason Jones')}
end
factory :client do
  name "Rich Homeowner"
  association :advisor
end
factory :user do
    email "jason@jones.com"
    password "testpassword"
    initialize_with {User.find_or_create_by_email('jason@jones.com')}
end

我的控制器:

class ClientsController < ApplicationController
  before_filter :authenticate_user!
 def destroy
    @client = current_user.advisor.clients.where(:id => params[:id]).first
    @client.destroy
    flash[:notice] = 'Client deleted.'
    redirect_to clients_path
  end

和我的控制器测试:

 describe "DELETE destroy" do
    it "should delete a client" do
        a = FactoryGirl.create(:advisor)
        c = FactoryGirl.create(:client, :advisor => a)
        login_user(a.user)
        expect{
          delete :destroy, :id => c.id
          response.should be_redirect
          assigns(:client).should eq(c)
        }.to change(Client, :count).by(-1)
      end
  end

login_user规范助手是它变得时髦的地方。 如果我取消注释下面的行,强制用户设置为 FactoryGirl 对象,则测试通过。如果我将其保留为注释,Devise 会尝试以传递的用户身份登录(我已经通过调试验证该用户是数据库中的同一用户),但它实际上并没有登录。在这两种情况下,sign_in调用实际上都返回相同的数组,但基于执行路径,控制器代码永远不会执行,因为 Devise 会重定向到登录页面。

def login_user(user=nil)
   @request.env["devise.mapping"] = Devise.mappings[:user]

   if user.nil?
     user = FactoryGirl.create(:user)
   end
   # user = FactoryGirl.create(:user) # uncommenting this line causes test to pass
   sign_in user
 end

如何让sign_in正常工作?

作为记录,当涉及到TDD for Rails时,我花了10分钟让我的实际代码正常工作,2个小时跳过箍让我的测试代码做它应该做的事情。

我最近开始尝试吞下TDD的哲学,并承认我和你一开始有一模一样的感觉。您的时间估计似乎非常准确,10 分钟的开发和 2 小时的测试用例实现。我的第一个建议是,就像生活中的许多事情一样,它会变得更好。当你第一次做出看似无害的改变,然后意识到你已经打破了一半的测试回归时,你会很高兴你吃了药丸。

话虽如此,这听起来像是一个警察,因为你在问为什么Devise不起作用,我的回答是:你不应该关心。明明你做错了什么,恐怕我从给出的信息中看不出是什么,但我想我无论如何都可以帮忙。

我在上面看到的唯一错误是您的规范正在测试至少四件事:

  1. 响应是重定向。
  2. 分配@client
  3. Client被摧毁。
  4. Devise提供正确的身份验证。

规范应该测试一件事,而且只测试一件事。尽管测试更多可能很诱人,但我不建议这样做。黄瓜或其他集成测试的是一堆东西,但不是规格。

Devise不是你应该在这里测试的东西,所以stub出来。我认为这样的事情会起作用:

before :each do
  @advisor = FactoryGirl.create(:advisor)
  controller.stub(:authenticate_user!).and_return(true)
  controller.stub(:current_user).and_return(@advisor.user)
end

在此之后,为要测试的三个内容创建三个不同的it "should" do块。

另一个提示是我认为您在定义FactoryGirl factory时不需要指定association。我认为这仅适用于多态关联。通常,您可以只提供不带值的关联名称,它将使用相同的名称运行工厂。只要注意无限循环。

我希望这有所帮助。

最新更新