在期望Rspec方法中何时使用花括号与括号?

时间:2014-02-05 03:04:18

标签: ruby rspec

我做了一次测试:

expect(@parser.parse('adsadasdas')).to raise_error(Errno::ENOENT)

它不起作用。我改为:

expect { @parser.parse('adsadasdas') }.to raise_error(Errno::ENOENT)

它有效。

我们什么时候使用花括号?什么时候使用带括号的括号?

4 个答案:

答案 0 :(得分:30)

为了回应OP的评论,我编辑并完全重写了我的答案。我意识到我的原始答案过于简单,以至于它被认为是不正确的。

你的问题实际上是由其他StackOverflow question解决的。

一张海报Peter Alfvin在他说:

时提出了一个很好的观点
  

至于规则,如果您正在尝试测试,则传递一个块或一个Proc   行为(例如,提出错误,改变一些价值)。否则,你   传递一个“常规”参数,在这种情况下,它的价值   论证是经过考验的。

你遇到这种现象的原因与引发错误有关。当您将@parser.parse('adsadasdas')作为参数(使用括号)传递给expect时,您实际上是在告诉ruby:

  1. 首先评估@parser.parse('adsadasdas')
  2. 获取结果并将其传递给expect
  3. expect应该看看这个结果是否符合我的期望(也就是说,Errno:ENOENT会被提出)。
  4. 但是,会发生什么:当ruby评估@parser.parse('adsadasdas')时,就会出现错误。 Ruby甚至没有机会将结果传递给expect。 (对于我们所关心的所有内容,您可以将@parser.parse('adsadasdas')作为参数传递给任何函数...例如multiply()capitalize())错误被引发,expect甚至都没有有机会完成它的工作。

    但是当你使用大括号将@parser.parse('adsadasdas')作为proc(代码块)传递给expect时,你告诉ruby的是:

    1. expect,准备好做一些工作。
    2. expect,我希望您跟踪评估@parser.parse('adsadasdas')时发生的情况。
    3. 好的,expect,刚刚评估的代码块是否会引发Errno:ENOENT错误?我原以为它会。
    4. 当您将代码块传递给expect时,您告诉expect您希望它检查结果行为,代码块执行所做的更改,然后让您知道如果它符合您提供的期望。

      当您将参数传递给expect时,您告诉 ruby​​ expect之前评估该参数是否达到某个值涉及,然后您将该值传递给expect以查看它是否符合某些期望。

答案 1 :(得分:6)

TL; DR:使用expect(exp)指定exp,并使用expect { exp }指定副作用exp执行时发生。


让我们解开一下。 RSpec的大多数匹配器都是 value 匹配器。它们匹配(或不匹配)任何ruby对象。相比之下,少数RSpec的匹配器只能与块匹配,因为它们必须在运行时观察块才能正常运行。这些匹配器涉及块执行时发生(或不发生)的副作用。除非传递一个块来执行,否则匹配器无法判断是否已发生命名副作用。让我们一个一个地考虑内置块匹配器(从RSpec 3.1开始):

raise_error

考虑可以从方法返回异常,这与引发异常不同。引发异常是一种副作用,只有匹配器通过执行具有适当rescue子句的块才能观察到异常。因此,此匹配器必须接收块才能正常工作。

throw_symbol

抛出符号类似于引发错误 - 它会导致堆栈跳转,这是一种副作用,只能通过在适当的catch块内运行块来观察。

change

对状态的突变是副作用。匹配器只能通过事先检查状态,运行块,然后检查状态来判断某个状态是否有变化。

output

I / O是副作用。要使output匹配器正常工作,必须使用新的$stdout StringIO`替换相应的流($stderrStringIO, execute the block, restore the stream to its original value, and then check the contents of the)。

yield_control / yield_with_args / yield_with_no_args / yield_with_successive_args

这些匹配器有点不同。 Yielding实际上并不是副作用(它实际上只是调用调用者提供的另一个函数的语法糖),但是通过查看表达式的返回值无法观察到屈服。为了使yield匹配器工作,它们提供了一个probe对象,您可以使用&probe语法将其作为块传递给测试方法:

expect { |probe| [1, 2, 3].each(&probe) }.to yield_with_successive_args(1, 2, 3)

所有这些匹配者有什么共同之处?他们都无法处理简单的ruby值。相反,他们都必须在适当的上下文中包裹一个块(即在值之前/之后挽救,捕获或检查)。

请注意,在RSpec 3中,我们added some logic为用户在使用给定匹配器的错误expect表单时提供明确错误。但是,在expect(do_something).to raise_error的特定情况下,我们无法为您提供明确的解释 - 如果do_something引发错误(如您所期望的那样......),那么错误在ruby评估to参数(raise_error匹配器)之前引发,因此RSpec无法检查匹配器以查看是否支持值或阻止期望。

答案 2 :(得分:2)

简而言之:

  • 使用花括号(块):当你想测试behavior
  • 如果要测试returned value
  • ,请使用括号

值得一读:As for rules, you pass a block or a Proc if you're trying to test behavior (e.g. raising errors, changing some value). Otherwise, you pass a "conventional" argument, in which case the value of that argument is what is tested. - from this answer

答案 3 :(得分:1)

在用括号写的测试中,代码正常执行,包括所有正常的错误处理。花括号语法定义了一个块对象,您可以在其上放置期望值。它封装了您希望被破坏的代码,并允许rspec捕获错误并提供自己的处理(在这种情况下,成功的测试)。

您也可以这样考虑:使用括号,代码在传递给expect方法之前执行,但是使用块,expect将运行代码本身。< / p>