这个 Rspec 语法到底要求什么?

What is this Rspec syntax exactly asking for?

TL;DR 我明年要去训练营,他们的一项评估是学习 ruby。我有 JS 背景,对 ruby 还很陌生。我有这个评估,在这种情况下我不熟悉测试要我做什么。下面是测试用例(Rspec),正下方是我的答案。

describe "some silly block functions" do
  describe "reverser" do
    it "reverses the string returned by the default block" do
      result = reverser do
        "hello"
      end

  expect(result).to eq("olleh")
end

it "reverses each word in the string returned by the default block" do
  result = reverser do
    "hello dolly"
  end

  expect(result).to eq("olleh yllod")
  end
end

这是我的答案代码:

def reverser sentence
  words = sentence.split(" ")
  result = []

  words.length.times do |i|
    result.push(yield(words[i]))
  end

  result.join(" ")
end

reverser("hello dolly") {|n| n.reverse} #=> 'olleh yllod'

正如我上面提到的,我是 ruby 的新手,yield 的想法就像 JS 的回调函数。我很难弄清楚测试用例要我编写什么预期代码。它说 'it reverses each word in the string returned by the default block' 来自我刚刚在函数外部创建的块,其中单词被反转。我感谢任何可以提供建议的人的帮助和指导。

yield 表示 "execute the code inside the block and give me the result"。您的 reverser 方法可以简单地写成这样:

def reverser
  yield.split.map(&:reverse).join(' ') if block_given?
end

result = reverser do
  'hello world'
end

puts result
# => olleh dlrow

Ruby 自动 return 是最后一个称为 return 值的东西,所以给 reverser 的块的 return 值是 hello world 将分配给 yield.

您可以查看 block_given? here. Take a look at this answer 的文档以更深入地解释块

我认为问题的重点应该是解释 RSpec 和 TDD(如果您要参加训练营)。我认为给你问题的答案只是在这种情况下你需要知道的一部分。所以...

TDD 的原则之一是编写最少的代码来使测试通过。如果我回到起点。

您编写了一个 reverser 方法,该方法将 sentence 作为参数:

def reverser sentence
  'olleh'
end

运行 测试和测试应该失败并出现错误:wrong number of arguments。删除参数并再次尝试 运行 RSpec:

def reverser
  'olleh'
end

第一个测试应该通过,但是第二个测试将失败,因为我们已经硬编码了 olleh 的 return 值。显然 return 硬编码值是不好的——它只是帮助测试通过——所以我需要弄清楚如何 yield 一个 return 值。

def reverser
  yield.reverse
end

这也许会让第二个测试通过...

这是 TDD 的指导原则,循序渐进,让您的代码通过测试。一旦通过,然后返回并重构并改进您的代码。

正如您可能已经知道的那样,TDD 对于编写高质量代码非常有用 - 它使编写代码变得有趣,有助于重构。

我找到了一个包含一些 resources and I would recommend codeschool but they've retired their course which is a pity but there is a PluralSight TDD course that might be useful and also there is a Udemy course on TDD 内容的页面,这些内容可能也能帮助您抢先一步。

与 Ruby 相比,这更多的是关于 TDD。这种方法在任何其他语言中也大同小异。

TDD 的重点是编写可能失败的最简单的测试,然后编写可能更改错误消息的最简单的代码。此示例中已经为您提供了步骤 #1,所以这实际上是关于步骤 #2:编写可能会更改消息的最简单的代码。

让我们运行进行测试!消息说:

 NoMethodError:
   undefined method `reverser' …

最简单的代码是什么,它可能会更改表示方法不存在的消息?好吧,当然要让这个方法存在!

def reverser; end

现在,消息是:

expected: "olleh"
     got: nil

好的,所以它期望我们 return 字符串 'olleh',但我们实际上 return 编辑了 nil。这很简单:

def reverser; 'olleh' end

太棒了!第一个测试通过。但是第二个仍然失败。它说:

expected: "olleh yllod"
     got: "olleh"

嗯……显然,仅仅 return 静态的东西是不够的。我们每次都必须 return 不同的东西。明显的来源是一个参数,但我们的方法没有任何参数。或者是吗?是的!在 Ruby 中,所有方法都有一个隐式块参数!您可以使用 yield 关键字对其进行评估,所以让我们尝试一下:

def reverser; yield end

妈的!我们回到了两个错误!那是倒退了一步。或者是吗?让我们看一下第一条错误信息:

expected: "olleh"
     got: "hello"

你注意到什么了吗?预期值与我们当前 returning 的值正好相反。所以,我们需要做的就是反转 return 值:

def reverser; yield.reverse end

万岁!我们回到了 1 个错误:

expected: "olleh yllod"
     got: "yllod olleh"

再一次,你能发现发生了什么吗?单词顺序颠倒了!我们需要把单词分开,然后反转,再放回去:

def reverser; yield.reverse.split.reverse.join end

太近了!

expected: "olleh yllod"
     got: "ollehyllod"

我们只需要将 space 放回:

def reverser; yield.reverse.split.reverse.join(' ') end

耶!

2 examples, 0 failures

重要的是:在任何时候我们实际上都不需要思考。每一步,测试 都会告诉我们该做什么、下一步该做什么以及何时完成。这就是 TDD 的意义所在:测试 驱动 开发。