【问题标题】:RSpec + Rubocop - why receive_message_chain is a code smell?RSpec + Rubocop - 为什么receive_message_chain 是代码异味?
【发布时间】:2018-12-06 09:19:49
【问题描述】:

我即将为我的自定义验证器编写规范,它使用此链检查 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 行。我在这里遗漏了什么吗?

【问题讨论】:

  • “链可以任意长,这使得以暴力方式违反得墨忒耳法则很容易,所以你应该考虑任何使用 receive_message_chain 的代码气味。[....] @987654328 @ 导致脆弱的例子”。取自relishapp.com/rspec/rspec-mocks/docs/working-with-legacy-code/…
  • 谢谢,我已经阅读了这两个来源,但是对于“更快”的扩展,我真的无能为力——我可以创建自己的方法并将 blob 传递给它,即会卧底打电话.filename.extension,但你觉得真的值得吗?

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


【解决方案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

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

【讨论】:

    猜你喜欢
    • 2012-07-13
    • 2017-04-10
    • 1970-01-01
    • 2021-11-04
    • 1970-01-01
    • 2011-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多