Rails 和 RSpec:在不同的命名空间(模块)中测试具有相同名称的控制器

Posted

技术标签:

【中文标题】Rails 和 RSpec:在不同的命名空间(模块)中测试具有相同名称的控制器【英文标题】:Rails and RSpec: Testing controllers with the same name in different namespace (module) 【发布时间】:2017-05-18 14:37:16 【问题描述】:

我有使用 RSpec 3.4.0 测试的 rails 4.1.16 API 应用程序,但在测试不同模块中的同名类时遇到问题。

结构是:

app/controllers/bar/notifications_controller.rb

class Bar::NotificationsController < ApiController
  ...
end

和不同模块中的同名控制器:

app/controllers/foo/bar/notifications_controller.rb

module Foo
  class Bar::NotificationsController < ApiController
    ...
  end
end

Foo 是一个新模块,还没有测试。 添加后,旧Bar::NotificationsController的所有相应控制器测试开始失败。

规范文件:

spec/controllers/bar/notifications_controller_spec.rb

require 'spec_helper'

describe Bar::NotificationsController, type: :controller do
  ...
end

该规范文件中的所有测试都失败并出现相同的错误:

RuntimeError:
   @controller is nil: make sure you set it in your test's setup method.

当我在Foo模块中更改控制器名称时问题不存在:

app/controllers/foo/bar/foo_notifications_controller.rb

module Foo
  class Bar::FooNotificationsController < ApiController
    ...
  end
end

我已经尝试在规范文件的顶部添加require 'bar/notifications_controller' 并将类名用作字符串describe "Bar::NotificationsController, type: :controller,但它没有解决问题(同样的错误)。

为什么会这样?解决办法是什么?

我想相信有一件小事我还没有尝试过,我不必为了使规范通过而用无意义的名称污染我的代码和结构。

非常感谢您的帮助!

【问题讨论】:

您可以尝试使用module Bar 来定义命名空间,而不是在类名本身中定义吗? 试试describe ::Bar::NotificationsController, type: :controller do 不幸的是它没有用。 【参考方案1】:

一般来说,我会在类定义中包含 all 命名空间。类似的东西:

app/controllers/foo/bar/notifications_controller.rb

class Foo::Bar::NotificationsController < ApiController
  ...
end

乍一看,这可能与以下内容相同:

app/controllers/foo/bar/notifications_controller.rb

module Foo
  class Bar::NotificationsController < ApiController
    ...
  end
end

事实上,这些是不同的。不同之处在于 Rails 如何处理常量的自动加载。我不会在这里详细介绍,因为它是一个较长的主题,并且在 web-o-sphere 中有很好的文章/帖子。

您可以找到关于 Rails 如何处理自动加载的好文章,例如 this one(或尝试谷歌搜索 rails constant loading

此外,正如文章所述,Ruby 常量加载的操作方式与 Rails 加载不同。可以在 here 找到有关 Ruby 常量加载的好信息(或尝试谷歌搜索 ruby constant loading)。

【讨论】:

谢谢,成功了!您能否简要解释一下为什么会发生这种情况?或者有关该主题的一些资源?我希望以两种方式编写的模块和类的行为方式相同,因为它们是相同的:|

以上是关于Rails 和 RSpec:在不同的命名空间(模块)中测试具有相同名称的控制器的主要内容,如果未能解决你的问题,请参考以下文章

Rails 3,RSpec 2.5:使用带有命名范围的 should_receive 或 stub_chain

Rails 模块作为严格的命名空间

失败/错误:需要'rspec/rails'类型错误:错误的参数类型类(预期模块)Rspec V3

Rails模块作为严格的命名空间

Rails url_for 和命名空间模型

如何避免 Rails 脚手架将模型放入命名空间