RSpec + Rubocop-为什么receive_message_chain是代码气味?

时间:2018-12-06 09:19:50

标签: ruby-on-rails rspec rubocop rubocop-rspec

我要为我的自定义验证器编写规格,该验证器使用此链来检查与ActiveStorage关联的文件是否为txt:

return if blob.filename.extension.match?('txt')

通常,我可以通过此调用将其存根:

allow(attached_file).to receive_message_chain(:blob, :byte_size) { file_size }

Rubocop认为这是冒犯,并向我指出了文档:https://www.rubydoc.info/gems/rubocop-rspec/1.7.0/RuboCop/Cop/RSpec/MessageChain

我将必须为blobbyte_size声明double并将它们存根在单独的行中,最后用5行代码代替1行。

1 个答案:

答案 0 :(得分:1)

为什么要避免对消息链进行存根?

  

我将不得不为blob和byte_size声明double并将其存根在单独的行中,最后以5行代码代替1。

实际上,这就是重点。在那有5条线可能会使您感到有些不安。这可以被认为是“正设计压力”。您的测试设置很复杂,它告诉您看一下实现。使用#receive_message_chains使我们对预先暴露出复杂交互的设计感到满意。

RSpec的一位作者在GitHub issue中对此进行了解释。

我该怎么办?

一种选择是在测试的设置阶段将夹具文件附加到记录:

before do
  file_path = Rails.root.join("spec", "fixtures", "files", "text.txt")

  record.attribute.attach(io: File.open(file_path), filename: "text.txt")
end

这将对验证器进行端到端测试,而不会产生任何存根。


另一种选择是提取一个命名方法,然后对它进行存根。

在您的验证器中:

def allowed_file_extension?
  blob.filename.extension.match?("txt")
end

在测试中:

before do
  allow(validator).to receive(:allowed_file_extension?).and_return(true)
end

这还有一个额外的好处,就是通过命名一个概念使代码更加清晰。 (即使使用测试治具,也没有阻止您添加此方法的方法。)