Rails 和 MiniTest:如何为 app/lib/mymodule 中的内容编写测试(Class 未找到)?

Rails and MiniTest: How to write tests for something in app/lib/mymodule (Class not found)?

Rails 5.2 这里。 我想测试在 app/lib/legacy/export.rb:

中定义的 class
# app/lib/legacy/export.rb
module Legacy
  class Export
    def initialize ; end
  end
end

但是,test/services/legacy_export_test.rb

中的测试
# test/services/legacy_export_test.rb
require 'test_helper'

class LegacyExportTest < ActiveSupport::TestCase
  test 'can be initialized' do
    Legacy::Export.new
  end
end

会吐NameError: uninitialized constant Legacy::Export.

如果我将 class 定义放在 app/lib/export.rb 中(并删除 module 定义),效果会很好。 我还可以在控制器和 rails 控制台 (rails c) 中引用此 class。

尝试从顶级 "namespace" (::Legacy::Export) 开始引用 class 也无济于事。我找到了有关如何在 test/ 文件夹中引用 lib 文件夹(和子目录)的问题的答案,但这不是我需要的。

require 'lib/legacy/export 会告诉我 cannot load such filerequire 'legacy/export'.

也会

我假设 Rails 和 MiniTest 的(自动)加载内容是相同的,但显然还有一些额外的配置需要完成。

必须做什么?我在哪里可以找到这些信息?

问题是您的 class 命名空间/class 路径与 Rails autoloading 开箱即用的方式不匹配。

当您使用之前未声明的 class 时,默认情况下 Rails 将查找特定路径(在 config.autoload_paths 上定义)

  • app/controllers
  • app/controllers/关注
  • app/models
  • app/models/关注
  • ...

当你第一次使用 User 时,因为它(还)没有定义,它会循环遍历这些路径并尝试要求 app/controllers/user.rb, app/controllers/concerns/user.rb, app/models/user.rb, 直到找到 User class

如果您的 class 命名空间为 Legacy::Export,那么它将查找 app/models/legacy/export.rb、app/models/concerns/legacy/ export.rb、app/controllers/legacy/export.rb 等

这就是它找不到您的 class 的原因:您的文件位于 app/lib,不在 Rails 用于查找的路径内。

有不同的解决方案:

选项#1

明确要求文件。 (Ruby 方式)

require_relative '../../app/lib/legacy/export'

选项#2

app/lib 添加到 autoload_path(在 config/application.rb 中) (Rails 方式)

module YourApp
  class Application < Rails::Application
    # ...
    config.autoload_paths << Rails.root.join("app/lib")
  end
end

选项#3

调整命名空间以匹配自动加载的预期(而不是更改配置)

示例:将您的文件移动到类似 app/models/legacy/export.rb

的位置