在使用Devise Helper Sign_In时,对于nil:NilClass,Rails 5集成测试失败,NoMethodError:unfined方法`[]='

人气:845 发布:2022-10-16 标签: ruby-on-rails integration-testing devise ruby-on-rails-5 warden

问题描述

我正在使用内置的Minitest编写一个Rails V5.1的集成测试。

以下是集成测试类:

require 'test_helper'

class PuppiesEndpointsTest < ActionDispatch::IntegrationTest

    include Devise::Test::IntegrationHelpers

    test "DELETE puppy" do
        marty = people(:marty)

        sign_in(marty)

        # delete puppies_delete_path(marty.puppies.first.id)
        # delete `/api/v1/puppies/destroy/${marty.puppies.first.id}.json`
        # delete puppies_path(marty.puppies.first.id)
        delete '/api/v1/puppies/destroy/6666.json'
        assert_response :success
    end

end

上面的所有路由,包括那些被注释掉的路由,都会导致相同的神秘错误:

Error:
PuppiesEndpointsTest#test_DELETE_puppy:
NoMethodError: undefined method `[]=' for nil:NilClass
    test/integration/puppies_endpoints_test.rb:17:in `block in <class:PuppiesEndpointsTest>'


bin/rails test test/integration/puppies_endpoints_test.rb:7

它没有提供堆栈跟踪或任何其他信息来诊断它到底在说什么。我使用byebug调试了marty变量,就在抛出错误的delete行之前。它显示了关联(装置)记录的预期Pupies数组。

我还在控制器操作的最顶端放置了一个byebug,该错误在到达该byebug之前未能通过测试,因此我认为这基本上排除了操作代码中的任何内容。

以下是我运行rake routes时看到的相关块:

                       PATCH      /api/v1/puppies/edit/:id(.:format)        puppies#update
                       DELETE     /api/v1/puppies/destroy/:id(.:format)     puppies#destroy
        puppies_create POST       /api/v1/puppies/create(.:format)          puppies#create

以下是我的路线文件中的实际内容:

  scope '/api' do
    scope '/v1' do
      devise_for :people

      patch 'puppies/edit/:id' => 'puppies#update'
      delete 'puppies/destroy/:id' => 'puppies#destroy'#, as: 'puppies_delete'
      post 'puppies/create' => 'puppies#create'
      ...

我完全搞不懂我收到这个错误的原因/原因。实际代码完全按照预期工作。

我的直觉是,可能有一个没有为测试环境设置的配置变量(我使用dotenv gem),但如果错误不会给我提供任何上下文,我不知道如何跟踪它。

更新

我已将此问题隔离为使用Devise Helpersign_in方法。当我删除此方法调用时,问题就消失了。

以下是有问题的测试类:

require 'test_helper'

class PuppiesEndpointsTest < ActionDispatch::IntegrationTest

    include Devise::Test::IntegrationHelpers

    test "do stuff" do
       ...

APP/CONTRONTROLLES/API_CONTROLER.rb:

class ApiController < ActionController::API
end

可能sign_in不适用于测试不从ActionController::Base继承的控制器

我将控制器更改为从ActionController::Base继承,但没有任何更改。我仍然无法在不收到该错误的情况下使用sign_in,但如果我"手动"post向登录终结点发出请求,它会起作用。

更新2 我发现了这个听起来与我的问题有关的设计问题:https://github.com/plataformatec/devise/issues/2065

推荐答案

看起来我找到了issue。显然,在rails-api模式下,ActionDispatch::Cookie和ActionDispatch::Session::CookieStore中间件被插入到中间件堆栈的末尾,这在正常的Rails模式下是不会发生的。

正因为如此,这些中间件包含在Warden::Manager之后,这会在请求规范中搞乱一些东西。

尝试在test.rb中设置

Rails.application.config.middleware.insert_before Warden::Manager, ActionDispatch::Cookies
Rails.application.config.middleware.insert_before Warden::Manager, ActionDispatch::Session::CookieStore

211