我正在阅读 Michael Hartl 的 Ruby on Rails 教程 的第 3.3 节,我们刚刚开始测试部分。在本节中,我们将在控制器 (StaticPagesController) 中对静态页面进行分组,并尝试手动向控制器添加“关于”操作。因为我们正在练习 TDD,所以我们首先编写一个失败的测试。但是,输出的错误消息非常长(我不知道这是否是标准的),我想知道是否有办法缩短输出。预先感谢!
test/controllers/static_pages_controller_test.rb:我们编写以下代码(为简洁起见,省略了之前的两个通过测试):
require "test_helper"
class StaticPagesControllerTest < ActionDispatch::IntegrationTest
test "should get about" do
get static_pages_about_url
assert_response :success
end
end
然后我在终端中运行以下命令来运行测试:
% rails test
正如预期的那样,终端的输出显示 1 个错误。但是,该错误非常长(太长了,以至于它不适合 VS Code 终端——我必须在系统终端中查看它),并且我必须向上滚动数百行才能看到有问题的错误的开始。
错误示例:
Minitest::UnexpectedError: NameError: undefined local variable or method `static_pages_about_url' for #<StaticPagesControllerTest:0x00007fefbd442320 @_routes=nil, @NAME="test_should_get_about", @failures=[#<Minitest::UnexpectedError: Unexpected exception>], @assertions=0, @integration_session=#<#<Class:0x00007fefbd441c40>:0x00007fefbd4414c0 @_routes=nil, @app=#<SampleApp::Application:0x00007fefbd2fc308 @_all_autoload_paths=["/Users/christophermarchant/Documents/odin-project/full-stack-ruby/rails-course/hartl_rails_tutorial/sample_app/environment/sample_app/app/channels", "/Users/christophermarchant/Documents/odin-project/full-stack-ruby/rails-course/hartl_rails_tutorial/sample_app/environment/sample_app/app/controllers", ... @stubs=#<Concurrent::Map:0x00007fefbcd08550 entries=0 default_proc=#<Proc:0x00007fefbcd084b0 /Users/christophermarchant/.rbenv/versions/3.0.3/lib/ruby/gems/3.0.0/gems/activesupport-6.1.5/lib/active_support/testing/time_helpers.rb:14>>>, @time=0.12419799994677305>
整个错误要长得多。
Rails 似乎正在检查并打印整个 StaticPagesControllerTest 对象及其所有属性。
主要问题:有没有办法更改某些配置,使 NameError 更短,如下所示?
NameError: undefined local variable or method `static_pages_about_url' for #<StaticPagesControllerTest:0x00007fefbd442320>
其他信息
Gemfile:
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
ruby '3.0.3'
gem 'rails', '~> 6.1.5'
gem 'puma', '~> 5.0'
gem 'sass-rails', '>= 6'
gem 'webpacker', '~> 5.0'
gem 'turbolinks', '~> 5'
gem 'jbuilder', '~> 2.7'
gem 'bootsnap', '>= 1.4.4', require: false
group :development, :test do
gem 'sqlite3', '~> 1.4'
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
end
group :development do
gem 'web-console', '>= 4.1.0'
gem 'rack-mini-profiler', '~> 2.0'
gem 'listen', '~> 3.3'
gem 'spring'
end
group :test do
gem 'capybara', '>= 3.26'
gem 'selenium-webdriver', '>= 4.0.0.rc1'
gem 'webdrivers', '~> 5.0'
gem 'rails-controller-testing', '~> 1.0', '>= 1.0.5'
gem 'minitest', '~> 5.15'
gem 'minitest-reporters', '~> 1.5'
gem 'guard', '~> 2.18'
gem 'guard-minitest', '~> 2.4', '>= 2.4.6'
end
group :production do
gem 'pg', '~> 1.3', '>= 1.3.4'
end
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
测试/test_helper.rb文件:
ENV['RAILS_ENV'] ||= 'test'
require_relative "../config/environment"
require "rails/test_help"
require "minitest/reporters"
class ActiveSupport::TestCase
# Run tests in parallel with specified workers
parallelize(workers: :number_of_processors)
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all
# Add more helper methods to be used by all tests here...
end
Minitest::Reporters.use!(
Minitest::Reporters::SpecReporter.new(:color => true),
ENV,
Minitest.backtrace_filter
)
系统和版本:
Ruby on Rails 6.1.5
红宝石3.0.3p157
macOS Big Sur 版本 11.6.4
采取蛮力方法并重写
Minitest::UnexpectedError
似乎有效。如果不这样做,我实际上会得到 20,000 行消息/回溯,滚动到顶部出现意外错误:
# place this module in your `test_helper.rb`
module Minitest
# copied from https://github.com/minitest/minitest/blob/ea9caafc0754b1d6236a490d59e624b53209734a/lib/minitest.rb#L841
# goal is to truncate the extremely long error message...
class UnexpectedError < Assertion
attr_accessor :error # :nodoc:
def initialize error # :nodoc:
super "Unexpected exception"
if SystemStackError === error then
bt = error.backtrace
new_bt = compress bt
error = error.exception "#{bt.size} -> #{new_bt.size}"
error.set_backtrace new_bt
end
self.error = error
end
def backtrace # :nodoc:
self.error.backtrace
end
BASE_RE = %r%#{Dir.pwd}/% # :nodoc:
def message # :nodoc:
bt = Minitest.filter_backtrace(self.backtrace).join("\n ")
.gsub(BASE_RE, "")
# truncate the message:
truncated = "#{self.error.class}: #{self.error.message.truncate(2000, omission: '... (truncated from test_helper.rb Minitest::UnexpectedError)')}\n #{bt.first(10)}"
# the original return value is here:
# "#{self.error.class}: #{self.error.message}\n #{bt}"
#
truncated
end
def result_label # :nodoc:
"Error"
end
end
end