【问题标题】:Rails 5 Integration test fails with NoMethodError: undefined method `[]=' for nil:NilClass when using Devise helper sign_inRails 5 集成测试失败,出现 NoMethodError:未定义方法 `[]=' for nil:NilClass when using Devise helper sign_in
【发布时间】:2019-03-04 09:13:30
【问题描述】:

我正在使用内置 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 在抛出错误的 delete 行之前调试了 marty 变量。它显示了相关(夹具)记录的预期小狗数组。

我还在控制器操作的最顶部放置了一个 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 助手 sign_in 方法。当我删除此方法调用时,问题就消失了。

这是有问题的测试类:

require 'test_helper'

class PuppiesEndpointsTest < ActionDispatch::IntegrationTest

    include Devise::Test::IntegrationHelpers

    test "do stuff" do
       ...

app/controllers/api_controller.rb:

class ApiController < ActionController::API
end

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

我将控制器更改为从 ActionController::Base 继承,但没有任何改变。我仍然无法使用sign_in 而不出现该错误,但如果我“手动”post 向 sign_in 端点发出请求,它会起作用。

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

【问题讨论】:

  • 只是好奇你创建了marty = people(:marty),然后使用emerson 登录,是有意的吗?
  • 控制器中是否有任何before_action 过滤器用于此操作?
  • 缺少很多代码可能来自哪里。您是否尝试过将 binding.pry 放在 marty = people(:marty) 之前并手动执行 hte 命令以缩小问题的根源?
  • @Hoa.Nguyen 抱歉,这是一个复制/粘贴错误。现已修复
  • @Vasilisa 该控制器具有:before_action :authenticate_person!

标签: ruby-on-rails devise ruby-on-rails-5 integration-testing warden


【解决方案1】:

看起来我找到了issue。显然,在 rails-api 模式下,ActionDispatch::Cookies 和 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

【讨论】:

  • 就是这样!你搞定了。谢谢。现在我们弄清楚了,我可能会向 Devise 项目提出问题。
  • 我从您的链接中看到它已经归档。也许我会提交一个 PR 来更新 README
  • @emersonthis 很乐意为您提供帮助!公关是个好主意,我认为
猜你喜欢
  • 2019-12-29
  • 1970-01-01
  • 1970-01-01
  • 2015-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-31
  • 2013-04-24
相关资源
最近更新 更多