ruby-on-rails 如何使测试引发404错误而不是ActiveRecord::RecordNotFound异常?

gblwokeq  于 2023-05-08  发布在  Ruby
关注(0)|答案(1)|浏览(113)

我正在尝试编写一个测试,以确认我的应用程序发送404 Not Found来响应对无效记录的请求(比如一个id=0记录)。
我的测试代码看起来像这样:

get '/pluralized_name_for_my_resource/0', as: :json
assert_response :not_found, "Doesn't return 404 Not Found for invalid id"

如果我将相应的URL插入浏览器,例如http://localhost:3000/pluralized_name_for_my_resource/0.json,则应用程序在内部引发activerecord异常(并向日志打印有关它的消息),但正确地响应为404 Not Found
但是,当我运行测试时,异常的处理方式却不同。测试中止并在第一个get '/pluralized_...行返回,并报告为错误而不是通过测试。
我怎样才能使我的测试环境以与我的开发环境相同的方式处理异常,以便我的测试通过?

sqxo8psd

sqxo8psd1#

我做了一些实验,给出了rails g scaffold foo和这个测试:

require "test_helper"

class FoosControllerTest < ActionDispatch::IntegrationTest
  setup do
    @foo = foos(:one)
  end

  test "should respond with not found" do
    get foo_url('xxxxxx'), as: :json
    assert_response :not_found
    assert_equal({ "status" => 404, "error"=>"Not Found"}, response.parsed_body)
  end
end

在默认设置下,ActiveRecord::RecordNotFound异常确实不会被异常处理程序捕获,并冒泡到测试中。

Error:
FoosControllerTest#test_should_respond_with_not_found:
ActiveRecord::RecordNotFound: Couldn't find Foo with 'id'=xxxxxx
    app/controllers/foos_controller.rb:63:in `set_foo'
    test/controllers/foos_controller_test.rb:9:in `block in <class:FoosControllerTest>'

config/environments/test.rb中改变config.consider_all_requests_localconfig.action_dispatch.show_exceptions似乎是可行的:

# Show full error reports and disable caching.
config.consider_all_requests_local       = false # was true
config.action_controller.perform_caching = false
config.cache_store = :null_store

# Raise exceptions instead of rendering exception templates.
config.action_dispatch.show_exceptions = true # was false

有了这两个变化,测试通过:

Running 1 tests in a single process (parallelization threshold is 50)
Run options: --seed 27622

# Running:

.

Finished in 0.270401s, 3.6982 runs/s, 7.3964 assertions/s.
1 runs, 2 assertions, 0 failures, 0 errors, 0 skips

然而,这样做可能不是最好的主意,因为应用程序中的异常通常会导致您的测试提前退出。一个简单的解决方法是使用assert_raise来捕获异常,当它冒泡到测试时:

require "test_helper"

class FoosControllerTest < ActionDispatch::IntegrationTest
  setup do
    @foo = foos(:one)
  end

  test "should respond with not found" do
    assert_raise(ActiveRecord::RecordNotFound) do
      get foo_url('xxxxxx'), as: :json
      assert_response :not_found
      assert_equal({ "status" => 404, "error"=>"Not Found"}, response.parsed_body)
    end
  end
end

相关问题