Ruby RSpec如何允许和期望为多个调用生成意外结果

Ruby RSpec如何允许和期望为多个调用生成意外结果,ruby,rspec,expectations,Ruby,Rspec,Expectations,我试图写一个测试来防止你做同样的事情两次(在本例中,在Tictatoe中在同一个方块上玩两次),但是RSpec语法让我困惑,我在他们的文档中看不到解决方案。我尝试了一些方法,但没有成功,这让我意识到我对RSpec语法的理解不如我想象的那么好 因为测试是针对递归方法的,所以很多错误并不像我希望的那样具有描述性,因为它们会导致程序崩溃,这使得很难隔离问题 我尝试测试/创建的方法最初看起来如下: 转身 your_turn unless play_on(square_at(get_row, get_sq

我试图写一个测试来防止你做同样的事情两次(在本例中,在Tictatoe中在同一个方块上玩两次),但是RSpec语法让我困惑,我在他们的文档中看不到解决方案。我尝试了一些方法,但没有成功,这让我意识到我对RSpec语法的理解不如我想象的那么好

因为测试是针对递归方法的,所以很多错误并不像我希望的那样具有描述性,因为它们会导致程序崩溃,这使得很难隔离问题

我尝试测试/创建的方法最初看起来如下:

转身

your_turn unless play_on(square_at(get_row, get_square))
结束

(如果未成功放置标记,play_on返回零)

在本例中,我正在测试一个模块,对于这个模块,您的方法是get_row和get_square,但是play_on和square_at是它要集成到的类中的方法,所以我在必要的地方存根(get方法也是如此,因为我不想得到RSpec的提示)

我尝试的第一个测试是:

如果一个玩家不能在广场上玩,它会重复这个过程

allow(human).to receive(:play_on).and_return(nil, :square)

expect(human).to receive(:your_turn).twice

human.your_turn
结束

测试失败,并表示只收到一次。我期望这种情况在最初的your_turn调用中出现,RSpec将stub play_on,返回nil,设置除非语句并重复your_turn调用,之后它将返回一个符号并防止任何进一步的递归。我误解了什么

在那次努力之后,我想出了一个似乎有效的怪物,但我不完全确定为什么:

允许(人)。接收(:获取行)和返回(1,2)

允许(人类)接收(:获取平方)和返回(2,2)

允许(人)。接收(:平方)。带有(1,2)。和返回(:零)

允许(人类)。接收(:square_at.),带有(2,2)。和返回(:square)

允许(人类)。接收(:播放)。使用(:平方)。和返回(:平方)

期待(人类)。接受(玩)。两次

人类,轮到你了

your_turn unless play_on(square_at(get_row, get_square))
这里的问题(除了丑陋之外)是我通过暴力比理解更有效,还有一些事情我不确定:

  • 为什么我不能在没有返回RSpec提示的情况下删除前两行?因为在第三行和第四行中,我将方法square_存根在,它将调用get_方法,为什么它们仍然被调用
  • 类似地,第五行第三行和第四行似乎覆盖了第三行和第四行,但我最初得到了最后一个“允许”返回(nil,:square),希望它能起作用。结果在我预期的两个转弯处打了三次电话给你,所以我取消了零,它通过了。我解析它的方式是,如果没有nil,play_on将立即返回:square,因此除非逻辑不会被触发,方法将终止。再说一遍,我误解了什么
  • 有没有一种更干净利落的方法来处理这两条“正方形”的允许线
谢谢大家


Sasha

我不理解你的问题(特别是第二个和第三个),但我相信你的问题很大程度上是因为你只中断了一个方法调用,Ruby不会计算方法调用参数


square\u之前调用
get\u row
get\u square
方法。Ruby从“右向左”解析语句,因此它首先调用
get_row
,然后调用
get_square
,最后调用
square_at
传递两个get_方法的结果。这可能会破坏您的测试,具体取决于这两种方法的功能,并解释为什么您需要前两个存根。

在第一个测试(失败的那一个)中,如果您执行…
allow(human.).to receive(:play_on.),with(any_args())and_return(nil,:square)
抱歉,过早返回键…不起作用-它仍然调用其中的所有三个参数,因此我收到两次提示,最后收到一条消息,说“undefined method`square_at` for#”,啊,是的,这似乎是我大多数问题的根源!我不能投票给你——希望其他人能代表我投票。你可能还不能投票给我,但你可以接受维克托的答案。答案左侧有一个复选框,您可以在其中执行此操作。