RSpec - 如果我避免使用let,let和before,如何实现相同的功能?

时间:2013-09-12 15:40:02

标签: ruby rspec

我听说在RSpec中避免its, let, let!, specify, before,subject是最佳做法。

关于let, let!before,如果不使用这些任务,我该如何执行设置任务?

6 个答案:

答案 0 :(得分:8)

写这些最佳实践的人实际上只想说“不要使用RSpec”。避免使用核心功能仍然是疯狂的,但仍然认为你可以很好地完成任务。你能链接到这些最佳实践吗?我喜欢阅读它们,看看它们是否合理,或者仅仅是一些j-random-guy的意见。

避免beforelet?什么?真的?

避免使用specify,我猜,它只是it的旧语法。

避免特定的subject电话?我想,如果你的代码生活在一个理想主义的幻想世界里。努力减少它并使用隐含主题?肯定。

避免its?这很棒!为什么要避免呢?自记单行规格?多可怕啊。

答案 1 :(得分:6)

来源:有些人询问了所有这些的来源。我认为这来自thoughtbot best practices guides

答案:在阅读该指南之后,我几乎感到非常恐惧,但在做了一些研究后,我发现了来自同一个人Let's Not的非常好解释的帖子。这是一篇非常好的阅读材料,对一般的测试和良好实践提出了很多有见地的建议。

对该指南存在一些普遍的误解。只是说“避免”而不是“不要使用”。结果代码将更清晰,更易于维护。 我将引用帖子反映的一些观点:

  • (...)RSpec的DSL有一些功能经常被过度使用,导致测试维护的增加和测试可读性的降低。
  • 直到你需要像分享示例那样突破大枪,避免使用像subject,let,it和之前的DSL构造。坚持你的老朋友:变量,方法和类。

这对我来说很有意义。 希望这会有所帮助。

答案 2 :(得分:1)

如果您真的想研究rspec的最佳实践,我使用的一些资源是:

答案 3 :(得分:1)

我绝对同意尼克,不应遵循这些指导原则。

我最近写了一篇关于以正确方式构建规范的博客文章。它有一个彻底的演练,即采用“糟糕的”书面测试套件并使其成为一个爆炸。

您可以阅读here

答案 4 :(得分:1)

  

我听说这是最佳做法

如果你能引用一些来源会很有帮助。我相信你听到的陈述非常不准确。

  

避免its

我个人不使用its,但这是一个偏好问题。自its is a short-hand method起,您通常可以使用扩展版本。

  

避免letlet!

没有理由避免它们。 official documentation并没有阻止他们,事实上他们正在积极宣传。

从技术上讲,您可以通过定义方法来替换它们。

let(:foo) { 1 }

“等效”
def foo
  @foo ||= 1
end

但正如您所看到的,使用let更方便有效。

  

避免specify

specifyit的别名。

  

避免before

这没有意义。如果需要,无法避免before,官方文档也不会弃用它。

  

避免subject

绝对错误。文档鼓励使用它。


底线。我坚信你听到的是假的。请查看the documentation以了解如何有效使用RSpec。

答案 5 :(得分:1)

因为这里没有答案是针对实际问题,而是针对所提及的做法发表意见,所以我觉得有必要再添加一个答案,即使距被问起已有7年6年了。

所有“有问题的” DSL方法都可以替换为普通的旧Ruby方法。您仍然可以保持DRY状态,而不必使用会使代码的不同部分转移注意力的方法。

  

以下代码直接从Noel Rappin的Rails 5 Test Prescriptions一书中提取

describe "estimates" do
  let(:project) { Project.new }
  let(:done) { Task.new(size: 2, completed: true) }
  let(:small_not_done) { Task.new(size: 1) }
  let(:large_not_done) { Task.new(size: 4) }

  before(:example) do
    project.tasks = [done, small_not_done, large_not_done]
  end

  it "can calculate total size" do
    expect(project.total_size).to eq(7)
  end

  it "can calculate remaining size" do
    expect(project.remaining_size).to eq(5)
  end
end

用普通的Ruby方法代替

describe "estimates" do

  it "can calculate total size" do
    project = build_new_project
    project.tasks = build_done_small_and_large_tasks

    expect(project.total_size).to eq(7)
  end

  it "can calculate remaining size" do
    project = build_new_project
    project.tasks = build_done_small_and_large_tasks

    expect(project.remaining_size).to eq(5)
  end

  def build_new_project
    Project.new
  end

  def build_new_task(size=1, completed=false)
    Task.new(size: size, completed: completed)
  end

  def build_done_small_and_large_tasks
    tasks = []
    tasks << build_task(2, true)
    tasks << build_task(1, false)
    tasks << build_task(4, false)
    tasks
  end
end

依我和Thoughtbot的观点,这种方法有很多优点:

  • 每个测试都讲述了一个有关如何使用稍后编写的代码的故事
  • 每个测试都是独立的且具有描述性,理想情况下,您不必浏览整个文件即可立即了解每个测试的内容(但这也取决于您编写良好测试的能力)
  • 示例之间没有依赖性
  • “神秘来宾” 反模式

另一方面,重点是要在每个测试中尽可能明确地显示每个测试阶段

  • 设置-获得正确的测试条件
  • 锻炼-执行您要测试的事情
  • 验证-验证练习是否达到了您的预期
  • 拆卸-撤消测试后不应持续的任何条件 (这应该由Rspec自动完成,但是任何明确的内容都可以放在after块中)

示例:

it "can calculate total size" do
  # Setup
  project = build_new_project
  project.tasks = build_done_small_and_large_tasks

  # Exercise and verification 
  # Exercise is the "total_size" method, because that is what we are testing
  # Verification is the expectations of what should happen after the exercise
  expect(project.total_size).to eq(7)
end
# Teardown is performed by Rspec, you may also perform it yourself in   after blocks

最后,一个公司的风格指南永远无法满足所有目的或其他公司的需求。据我所知,这种方法对于测试驱动的开发特别有用,在该开发中,代码必须由每个失败的测试所建议的修复测试的驱动。因此,说您不应遵循这种方法是很主观的。它有很好的论据,也有一些缺点,一如既往,您应该权衡它们,并坚持最适合自己的方法。就我而言,我发现这些测试更易于阅读,对于理解应用程序的每个模块更有用,而不是简单地在出现问题时通知您,我喜欢编写可记录自身的代码。这种方法将使您清楚地看到将来的代码将如何使用以及每种情况的预期结果。 RSpec不只是DSL方法。

有关TDD的更多信息以及如何遵循这种测试方法,请查看如何Tell a Story With Your Tests