Rails 5集成测试失败,出现NoMethodError:使用Devise helper sign_in时nil:NilClass的未定义方法'[] ='

时间:2019-03-04 09:13:31

标签: ruby-on-rails devise ruby-on-rails-5 integration-testing 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变量。它显示了相关(夹具)记录的预期小狗数组。

我还在控制器动作的最顶部放置了一个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 我发现了这个与我的问题有关的Devise问题:https://github.com/plataformatec/devise/issues/2065

1 个答案:

答案 0 :(得分:1)

好像我找到了issue。显然,在rails-api模式下,将ActionDispatch :: Cookies和ActionDispatch :: Session :: CookieStore中间件插入中间件堆栈的末尾,这在正常的Rails模式下不会发生。

由于这个原因,那些中间件包含在Warden :: Manager之后,该中间件弄乱了请求规范中的某些内容。

尝试在test.rb中设置

layout = dict(yaxis=dict(title="Percents values",
                         # Choose what you want to see on yaxis! In this case list
                         tickvals=[i for i in range(len(percentage_difference))],
                         ticktext=percentage_difference
                         )
              )