【问题标题】:How do I make the gem WebMock work with json that includes [square brackets]?如何使 gem WebMock 与包含 [方括号] 的 json 一起使用?
【发布时间】:2018-10-05 03:20:14
【问题描述】:

有问题的 Rails 应用在测试中使用了 Rspec、Capybara 和 WebMock。

在一个测试场景中,此代码有效:

response = RestClient.post 'the.domain.com', 
  {
    "dados": {
      "head": {
         "servico": "autenticacao",
         "chave": ""
       },
       "data": {
         "empresa": "my_name",
         "login": "my_login",
         "senha": "my_password"
       }
     }
   }.to_json

RSpec.configure do |config|
  config.before(:each) do
    stub_request(:any, 'the.domain.com').
      with( body: hash_including(
        {"dados": {
          "head": {
            "servico": "autenticacao",
            "chave": ""
          },
          "data": {
            "empresa": "my_name",
            "login": "my_login",
            "senha": "my_paasword"
          }
        }}.to_json
      ) ).to_return(
        status: 200,
        body: {"dados": {"btms": {"chave": "returned_key"}}}.to_json,
        headers: {}
      )
  end
end

但是,在同一场景中,这发生在之后,不会:

data = []
data << {
  "cdg_tipo_transporte": "3"
}

response = RestClient.post 'the.domain.com',
  {
    "dados": {
      "head": {
        "servico": "reserva_salva_lote",
        "chave": response["dados"]["btms"]["chave"]
      },
      "data": data
    }
  }.to_json

RSpec.configure do |config|
  config.before(:each) do
    data = []
    data << {
      "cdg_tipo_transporte": "3"
    }
  stub_request(:any, 'the.domain.com').
    with( body: hash_including(
      {"dados": {
        "head": {
          "servico": "reserva_salva_lote",
          "chave": "returned_key"
        },
        "data": data
      } }.to_json
    ) ).to_return(
      status: 200,
      body: {"Status?": "OK"}.to_json,
      headers: {}
  )
  end
end

我得到的错误是关于如何禁用真正的 HTTP 连接,这是一个未注册的请求。我认为这意味着 Rails 和/或 WebMock 与 json 不匹配。

我研究了不同的事物并尝试了不同的事物。似乎方括号是问题所在。当我在没有它们的情况下构建任何东西时,它都会起作用。当我把它们放回去时,代码又中断了。

在这种情况下如何使用方括号?我需要它们在那里,因为我要发布到的真正 API 需要这种格式。

顺便说一句,开发环境与实际的 API 进行通信,并且代码运行良好。人体测试是完美的。只是自动测试不断失败!

更新

这是错误堆栈:

保存响应的变量为&lt;WebMock::NetConnectNotAllowedError: Real HTTP connections are disabled. Unregistered request:,然后显示请求、建议的存根(与我的匹配)和已注册的存根。

在下面,我得到:

#<ActionDispatch::Cookies::CookieOverflow: ActionDispatch::Cookies::CookieOverflow>
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/actionpack-5.1.6/lib/action_dispatch/middleware/cookies.rb:594:in `commit'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/actionpack-5.1.6/lib/action_dispatch/middleware/cookies.rb:465:in `[]='
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/actionpack-5.1.6/lib/action_dispatch/middleware/session/cookie_store.rb:117:in `set_cookie'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/rack-2.0.5/lib/rack/session/abstract/id.rb:363:in `commit_session'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/rack-2.0.5/lib/rack/session/abstract/id.rb:234:in `context'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/rack-2.0.5/lib/rack/session/abstract/id.rb:226:in `call'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/actionpack-5.1.6/lib/action_dispatch/middleware/cookies.rb:613:in `call'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/actionpack-5.1.6/lib/action_dispatch/middleware/callbacks.rb:26:in `block in call'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:97:in `run_callbacks'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/actionpack-5.1.6/lib/action_dispatch/middleware/callbacks.rb:24:in `call'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/actionpack-5.1.6/lib/action_dispatch/middleware/debug_exceptions.rb:59:in `call'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/actionpack-5.1.6/lib/action_dispatch/middleware/show_exceptions.rb:31:in `call'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/railties-5.1.6/lib/rails/rack/logger.rb:36:in `call_app'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/railties-5.1.6/lib/rails/rack/logger.rb:24:in `block in call'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/activesupport-5.1.6/lib/active_support/tagged_logging.rb:69:in `block in tagged'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/activesupport-5.1.6/lib/active_support/tagged_logging.rb:26:in `tagged'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/activesupport-5.1.6/lib/active_support/tagged_logging.rb:69:in `tagged'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/railties-5.1.6/lib/rails/rack/logger.rb:24:in `call'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/actionpack-5.1.6/lib/action_dispatch/middleware/remote_ip.rb:79:in `call'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/actionpack-5.1.6/lib/action_dispatch/middleware/request_id.rb:25:in `call'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/rack-2.0.5/lib/rack/method_override.rb:22:in `call'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/rack-2.0.5/lib/rack/runtime.rb:22:in `call'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/activesupport-5.1.6/lib/active_support/cache/strategy/local_cache_middleware.rb:27:in `call'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/actionpack-5.1.6/lib/action_dispatch/middleware/executor.rb:12:in `call'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/actionpack-5.1.6/lib/action_dispatch/middleware/static.rb:125:in `call'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/rack-2.0.5/lib/rack/sendfile.rb:111:in `call'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/railties-5.1.6/lib/rails/engine.rb:522:in `call'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/rack-2.0.5/lib/rack/urlmap.rb:68:in `block in call'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/rack-2.0.5/lib/rack/urlmap.rb:53:in `each'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/rack-2.0.5/lib/rack/urlmap.rb:53:in `call'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/capybara-3.2.1/lib/capybara/server/middleware.rb:44:in `call'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/puma-3.11.4/lib/puma/configuration.rb:225:in `call'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/puma-3.11.4/lib/puma/server.rb:632:in `handle_request'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/puma-3.11.4/lib/puma/server.rb:446:in `process_client'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/puma-3.11.4/lib/puma/server.rb:306:in `block in run'
/Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/puma-3.11.4/lib/puma/thread_pool.rb:120:in `block in spawn_thread'

Failure/Error: raise CookieOverflow if options[:value].bytesize > MAX_COOKIE_SIZE

ActionDispatch::Cookies::CookieOverflow:
   ActionDispatch::Cookies::CookieOverflow
 # /Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/rack-2.0.5/lib/rack/session/abstract/id.rb:363:in `commit_session'
 # /Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/rack-2.0.5/lib/rack/session/abstract/id.rb:234:in `context'
 # /Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/rack-2.0.5/lib/rack/session/abstract/id.rb:226:in `call'
 # /Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/railties-5.1.6/lib/rails/rack/logger.rb:36:in `call_app'
 # /Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/railties-5.1.6/lib/rails/rack/logger.rb:24:in `block in call'
 # /Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/railties-5.1.6/lib/rails/rack/logger.rb:24:in `call'
 # /Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/rack-2.0.5/lib/rack/method_override.rb:22:in `call'
 # /Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/rack-2.0.5/lib/rack/runtime.rb:22:in `call'
 # /Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/rack-2.0.5/lib/rack/sendfile.rb:111:in `call'
 # /Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/railties-5.1.6/lib/rails/engine.rb:522:in `call'
 # /Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/rack-2.0.5/lib/rack/urlmap.rb:68:in `block in call'
 # /Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/rack-2.0.5/lib/rack/urlmap.rb:53:in `each'
 # /Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/rack-2.0.5/lib/rack/urlmap.rb:53:in `call'
 # /Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/capybara-3.2.1/lib/capybara/server/middleware.rb:44:in `call'
 # /Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/puma-3.11.4/lib/puma/configuration.rb:225:in `call'
 # /Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/puma-3.11.4/lib/puma/server.rb:632:in `handle_request'
 # /Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/puma-3.11.4/lib/puma/server.rb:446:in `process_client'
 # /Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/puma-3.11.4/lib/puma/server.rb:306:in `block in run'
 # /Users/ViviPoit/.rvm/gems/ruby-2.3.7/gems/puma-3.11.4/lib/puma/thread_pool.rb:120:in `block in spawn_thread'

【问题讨论】:

  • 你能显示错误的堆栈跟踪吗? (错误名称、行号等)您正在对期望 "chave": "1234abcd" 的请求存根,为什么不直接使用它而不是 "chave": response["dados"]["btms"]["chave"]
  • 这可能吗?在测试本身期间分配的存根中有一个变量?我不能硬编码"chave",因为真正的代码每次都需要从API中获取。
  • 你在做真正的测试请求吗?这是个坏主意。错误提示 Real HTTP connections are disabled,您不应该在测试中执行真正的 HTTP 请求。另外,那是你的真实代码吗?或者你删除了一些部分并混合它们?照原样复制您的规范。
  • 我没有在测试中做真正的 HTTP。我的意思是应用程序每次都需要在生产中获取这个 "chave" 值,所以我的测试不应该每次都模拟这种获取吗?
  • response["dados"]["btms"]["chave"] 之前,response 中有什么内容?它实际上是一个哈希吗?你确认了吗? response["dados"]["btms"]["chave"] 是否如您所愿返回“returned_key”?您应该在调用 RestClient post 方法之前创建散列并检查散列实际上是您想要的。

标签: ruby-on-rails json webmock


【解决方案1】:

hash_including 需要键名和键值对来匹配,你将 {...}.to_json 传递给它,所以它会尝试匹配整个 json 值作为键。

另外,您的第二个请求存根期望 dados.head.chave 等于 "1234abcd",但第一个存根在 response["dados"]["btms"]["chave"] 中返回 "returned_key",显然存根不匹配导致 WebMock::NetConnectNotAllowedError

【讨论】:

  • 抱歉,这是一次糟糕且失败的尝试,在这里没有实际的类似键的值。它们在我的代码中匹配。如前所述,当我删除方括号时,代码有效,所以我知道"chave" 不是问题。
  • 刚刚注意到您将{..}.to_json 传递给hash_including,尝试匹配哈希
  • 成功了!不使用hash_including 使其正确通过。有没有地方可以找到对此的解释?因为所有其他模拟都使用hash_including。没有它,我无法让其他模拟工作。现在,有了这些 [方括号],把它拿走是什么有效的方法?!我很想有一个资源来帮助我更好地理解这一点。另外,如果您将其添加到您的答案中,我可以选择它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-05
  • 1970-01-01
相关资源
最近更新 更多