【问题标题】:Rubocop 25 line block size and RSpec testsRubocop 25 线块大小和 RSpec 测试
【发布时间】:2023-03-21 06:45:02
【问题描述】:

典型的 RSpec 单元测试广泛使用嵌套的 Ruby 块来构建代码并利用 DSL“魔法”让规范像 BDD 语句一样读取:

describe Foo do
  context "with a bar" do
    before :each do
      subject { Foo.new().add_bar }
    end

    it "looks like a baz" do
      expect # etc

在理想的规范中,每个示例都可以相对简短而精确。然而,外部块似乎通常会增长到 100 行以上,因为 RSpec 结构以这种方式工作,并且不采用很多规范示例,每个示例都可能有几行特定设置,以到达 describe 块与所描述主题的代码大小相同或更大。

最近的 Rubocop 升级引入了一条新规则,即块不应超过 25 行。我不确定它的基本原理,因为它没有在Ruby style guide 中列出。我明白为什么它可能是一件好事,并添加到默认规则集中。但是,升级后,我们的 Rubocop 测试多次失败,并显示类似 tests/component_spec.rb:151:3: C: Block has too many lines. [68/25] 的消息

使用 Rubocop 等代码度量工具,我喜欢拥有“使用默认值,链接到样式指南,完成工作”的策略。 (主要是因为争论制表符与空格和其他细节是在浪费时间,而 IME 永远不会得到解决)这显然是不可能的,我们的两个核心数据质量工具不同意代码布局方法 - 或者至少这就是我解释结果的方式,我认为我们编写规范的方式没有任何本质上的错误。

作为回应,我们简单地将 Rubocop 块大小规则设置为高阈值。但这让我想知道——我错过了什么? RSpec 是否在代码布局中使用了一种现在已经名誉扫地的方法,在我们的 RSpec 测试中,我必须有哪些合理选项来减少块大小?我可以看到重组代码以避免大块的方法,但它们毫无例外都是丑陋的黑客,纯粹是为了满足 Rubocop 的规则,例如将所有块分解为辅助函数:

def looks_like_a_baz
  it "looks like a baz" do
         expect # etc
  end
end

def bar_context
  context "with a bar" do
    before :each do
      subject { Foo.new().add_bar }
    end
    looks_like_a_baz
  end
end


describe Foo do
  bar_context
  # etc

。 . .我的意思是,这是可行的,但是以这种方式将一堆规范示例转换为辅助函数似乎与 RSpec 设计所鼓励的可读方法相反。

除了想办法忽略它,我还能做些什么吗?


我在这里能找到的关于这个主题的最接近的现有问题是RSpec & Rubocop / Ruby Style Guide,这看起来可以通过编辑测试模板来解决。

【问题讨论】:

  • default settings 排除spec/ 下的文件。
  • @Stefan:啊,所以我们对test/ 的使用让我们暴露了这一点。 . .很高兴知道。这意味着 Rubocop 作者承认 RSpec 代码有些不同,我们也应该这样做。

标签: ruby rspec rubocop


【解决方案1】:

如果一个特定的块通常太长,我会指定它而不是文件

Metrics/BlockLength:
  IgnoredMethods: ['describe', 'context']

【讨论】:

  • 取决于块名而不是文件名更准确,所以我认为这个答案更好。
  • ExcludedMethods 已重命名为 IgnoredMethods
【解决方案2】:

最近的 Rubocop 升级引入了一条新规则,即块不应超过 25 行。我不确定它的基本原理,因为它没有在 Ruby 样式指南中列出。

过去所有的警察都基于 The Ruby Style Guide,而 RuboCop 是一种遵守社区规定的做法的方式。

从那时起,方向发生了变化,RuboCop 的范围已经扩大,以帮助开发人员确保其代码库的总体一致性。这导致了两件事:

  1. 警察(甚至那些基于 Ruby 风格指南的警察)现在大多是可配置的。
  2. 对于 Ruby 样式指南中未提及但对于在项目中强制执行一致性仍然有用的东西,有一些警察。

这个警察属于第二类。

RSpec 是否在代码布局中使用了一种现在已经不可信的方法,在我们的 RSpec 测试中我有哪些合理的选择来减少块大小?

简短的回答是否定的。 DSL 仍然很酷。 :-)

这个警察的目标是命令式编程意义上的大块。作为一般指南,它不适用于通常是声明性的 DSL。例如,在 Rails 中有一个很长的 routes.rb 文件是完全良性的。这只是大型应用程序的自然结果,而不是违反样式。 (而且进行大量测试真是太棒了。)

现在,RuboCop 非常聪明,但它不知道什么是 DSL,所以我们不能自动忽略它们。有人可能会争辩说,我们可以排除流行框架的 DSL 入口方法,例如 Rails 路由和 RSpec 规范。不这样做的原因主要是:

  1. 假阴性。任何类都可以实现一个方法,采用一个块,同名。
  2. RuboCop 是一个 Ruby 分析工具,不应该真正了解外部库。 (在我们拥有适当的扩展系统之前,排除/spec 目录是一种礼貌,这可以由rubocop-rspec gem 处理。)

我的意思是,这是可行的,但是以这种方式将一堆规范示例转换为辅助函数似乎与 RSpec 设计所鼓励的可读方法相反。

底线是:RuboCop 可以帮助我们编写更好的代码。如果我们的应用程序设计在其他方面是合理的,并且我们发现自己只是为了取悦 RuboCop,而使事情变得不那么可读,那么我们应该过滤、配置或禁用 cop。 :-)

作为回应,我们简单地将 Rubocop 块大小规则设置为高阈值。但这让我想知道 - 我错过了什么?

这是一个相当生硬的工具,正如您所暗示的那样,您可能会因此而产生一些误报。这个警察有两种误报:

  1. 包含纯声明性 DSL 的文件,例如Rails 路线、RSpec 规范。
  2. 将声明性 DSL 混合到大多数命令式代码中的文件,例如Rails 模型中的aasm 状态机声明。

在第一种情况下,最好的解决方案是排除文件或目录,在第二种情况下使用内联禁用。

在你的情况下,你应该更新你的.rubocop.yml

Metrics/BlockLength:
  Exclude:
    - 'Rakefile'
    - '**/*.rake'
    - 'test/**/*.rb'

(请注意,您需要从默认配置中重新迭代基本排除项,因为该列表将被覆盖。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-02
    • 2010-12-05
    相关资源
    最近更新 更多