【问题标题】:ActionDispatch::IntegrationTest suppresses exceptionsActionDispatch::IntegrationTest 抑制异常
【发布时间】:2018-02-14 13:50:28
【问题描述】:

在调试失败的集成测试时,我一直遇到同样的问题,即我的代码中引发的异常被抑制并且未显示在测试输出中。

例如,对于以下控制器和测试:

class RegistrationController::ApplicationController
  def create
    # some code that raises an exception
  end
end
class RegistrationFlowTest < ActionDispatch::IntegrationTest

  test 'user registers successfully' do
    post sign_up_path, params: { username: 'arnold', password: '123' }
    assert_response :success  
  end

end

输出类似于

Minitest::Assertion: Expected response to be a <2XX: success>, but was a <500: Internal Server Error>

有没有办法查看确切引发的异常?而不仅仅是HTTP响应码的区别?

谢谢!

西蒙

【问题讨论】:

  • 可能只是你在参数上遗漏了一个冒号,所以不要post sign_up_path, params { username: 'arnold', password: '123' },试试post sign_up_path, params: { username: 'arnold', password: '123' },另外检查sign_in_path。
  • 不,只是写问题时的一个错字,但很好:)

标签: ruby-on-rails ruby ruby-on-rails-5 integration-testing actiondispatch


【解决方案1】:

我推荐的解决这个问题的方法是实际解析 Rails 提供的响应(至少在 testdevelopment 环境中默认),其中包括错误的堆栈跟踪,并在测试的情况下处理它失败。这样做的好处是,当出现不会导致测试失败的错误时(例如,您有意测试如何处理失败的场景),它不会输出堆栈跟踪。

我制作的这个小模块将允许您调用 assert_response_with_errors 来断言对调用的响应,但当响应与您的预期不符时,以可读格式输出异常消息和堆栈跟踪。

module ActionDispatch
  module Assertions
    module CustomResponseAssertions
      # Use this method when you want to assert a response body but also print the exception
      # and full stack trace to the test console.
      # Useful when you are getting errors in integration tests but don't know what they are.
      #
      # Example:
      # user_session.post create_gene_path, params: {...}
      # user_session.assert_response_with_errors :created
      def assert_response_with_errors(type, message = nil)
        assert_response(type, message)
      rescue Minitest::Assertion => e
        message = e.message
        message += "\nException message: #{@response.parsed_body[:exception]}"
        stack_trace = @response.parsed_body[:traces][:'Application Trace'].map { |line| line[:trace] }.join "\n"
        message += "\nException stack trace start"
        message += "\n#{stack_trace}"
        message += "\nException stack trace end"
        raise Minitest::Assertion, message
      end
    end
  end
end

要使用它,您需要在 Rails 将其堆栈加载到您的 test_helper.rb 之前将其包含到 ActionDispatch::Assertions 中。因此,只需将包含添加到您的 test_helper.rb 中,如下所示:

ActionDispatch::Assertions.include ActionDispatch::Assertions::CustomResponseAssertions
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
...

【讨论】:

    【解决方案2】:

    这是因为 Rails 控制器默认处理异常并引发 500 状态,使异常对测试套件不可见(如果在模型的单元测试中引发错误,这将非常有用)。 here 讨论了在测试套件中禁用此功能的选项或替代解决方法。

    该链接中的关键代码行,应添加到test/integration/integration_test_helper.rb

    ActionController::Base.class_eval do
      def perform_action
        perform_action_without_rescue
      end
    end
    
    Dispatcher.class_eval do
      def self.failsafe_response(output, status, exception = nil)
        raise exception
      end
    end
    

    编辑:我注意到该链接现在已经很旧了。我对 Rack 非常熟悉,所以虽然第一个块对我来说看起来不错,但我不确定第二个块是否仍然是最新的。如果需要更新,您可能需要查看 the relevant current Rails guide

    【讨论】:

    • 我收到了Uncaught exception: uninitialized constant Dispatcher 。那篇文章确实很老了。在导轨指南中也找不到任何有用的东西。有一个名为ActionDispatch::ShowExceptions 的中间件,但它已经包含在我的项目中。我对测试环境也有如下配置:config.action_dispatch.show_exceptions = true
    • 你试过关于控制器的第一个块吗?
    • 我现在做了,没区别:(
    • @rwold 我对这个问题的最大问题是,如果您正在测试的场景是您期望出现错误 HTTP 状态的场景(例如,测试上传格式无效的文件),它将无法工作) 但不是产生的错误 HTTP 状态(例如身份验证失败)。如果您看一下我的回答,它将允许您测试错误状态并在状态不是您期望的状态时仍然记录错误堆栈跟踪。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-18
    • 1970-01-01
    • 2011-12-12
    • 2011-04-19
    • 2012-03-04
    • 2019-12-03
    相关资源
    最近更新 更多