Rubocop 25线块尺寸和RSpec测试

Nei*_*ter 60 ruby rspec rubocop

典型的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
Run Code Online (Sandbox Code Playgroud)

在理想规范中,每个示例可以相对较短且精确.然而,似乎通常将外部块增加到100行以上,因为RSpec结构以这种方式工作,并且不需要许多规范示例,每个示例可能具有几行特定设置,以获得describe块,即与所描述的主题的代码相同或更大.

Rubocop最近的一次升级带来了新的规则,即块不应超过25行.我不确定它的基本原理,因为它没有在Ruby样式指南中列出.我可以看到为什么它可能是一件好事,并添加到默认规则集.但是,在升级之后,我们的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
Run Code Online (Sandbox Code Playgroud)

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

除了找到忽视它的方法之外,还有什么我可以做的吗?


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

J. *_*tte 90

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

Metrics/BlockLength:
  ExcludedMethods: ['describe', 'context']
Run Code Online (Sandbox Code Playgroud)

  • 确切地说,取决于块名而不是文件名,所以我认为这个答案更好。 (6认同)
  • “ExcludedMethods”已重命名为“IgnoredMethods” (6认同)

Dre*_*nmi 78

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

过去,所有的警察都是基于"红宝石风格指南",而RuboCop是一种遵循社区规定的做法的方式.

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

  1. 警察(即使是那些基于红宝石风格指南的人)现在大部分都是可以配置的.
  2. 对于Ruby样式指南中未提及的内容,有警察,但仍然有助于强制项目的一致性.

该警察属于第二类.

RSpec是否使用了现在已经失去信誉的代码布局方法,以及我在RSpec测试中减少块大小的合理选择是什么?

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

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

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

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

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

底线是:RuboCop可以帮助我们编写更好的代码.如果我们的应用程序设计是合理的,并且我们发现自己只是为了取悦RuboCop而不那么可读,那么我们应该过滤,配置或禁用警察.:-)

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

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

  1. 包含纯声明性DSL的文件,例如Rails路由,RSpec规范.
  2. 具有声明性DSL的文件混合成大多数命令式代码,例如aasmRails模型中的状态机声明.

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

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

Metrics/BlockLength:
  Exclude:
    - 'Rakefile'
    - '**/*.rake'
    - 'test/**/*.rb'
Run Code Online (Sandbox Code Playgroud)

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