在浏览RSpec Book时,我遇到了as_null_object方法。我不明白这本书提供的解释为什么需要它:
...最简单的方法是告诉双输出只监听我们告诉它的消息并忽略任何其他消息。
但为什么示例代码失败了?当我们在每个示例中调用double('output')
时,我们不是为每个示例创建一个新的双重对象并向其发送一条消息吗?
我想要的是对示例代码失败的原因以及as_null_object
如何解决问题的更深入的解释(而不是本书)。
it "sends a welcome message" do
output = double('output')
game = Game.new(output)
output.should_receive(:puts).with('Welcome to Codebreaker!')
game.start
end
it "prompts for the first guess" do
output = double('output')
game = Game.new(output)
output.should_receive(:puts).with('Enter guess:')
game.start
end
本书试图在前面的部分解释错误的原因,但我不明白这个解释。
我们已经告诉第一个例子中的双重期望
一无所知puts
“欢迎使用Codebreaker!”我们满足了这个要求,但我们只是告诉它期待“欢迎使用Codebreaker!”它对“输入猜测:”类似地,第二个示例中的double需要“输入猜测:”,但它获得的第一条消息是“欢迎使用Codebreaker”。
答案 0 :(得分:2)
当你使用output = double('output')
创建一个double并将其传递给Game.new(output)
中的新游戏时,该double将收到它在codebreaker游戏代码中传递的每条消息。您尚未包含它,但start
方法具有以下代码:
module Codebreaker
class Game
...
def start
@output.puts 'Welcome to Codebreaker!'
@output.puts 'Enter guess:'
end
end
end
在这里,请记住已将output
分配给@output
的{{1}}方法中的实例变量game
,因此在每个规范中都会调用它两条消息,首先是“欢迎使用Codebreaker!”,然后是“输入猜测:”。
如果没有initialize
,as_null_object
double会在收到除预期之外的任何内容时失败,即在第一个规范中除了'Welcome to Codebreaker'之外的其他内容!在第二个规范中除了“输入猜测:”以外的任何内容。通过在double上使用output
,您可以让它坐下来等待并忽略除预期之外的任何内容。这避免了上述问题。
希望有所帮助。
答案 1 :(得分:1)
我同意这个解释并不清楚。以下是我理解的内容,或许与shioyama的答案相结合,可以实现此次点击。
当您创建规范时,您说输出将包含预期的短语,但并不是说它只包含预期的短语。因此,假设您通过将所有期望放在一个示例中来解决错误,例如:
it "gets expected output" do
output = double('output')
game = Game.new(output)
output.should_receive(:puts).with('Welcome to Codebreaker!')
output.should_receive(:puts).with('Enter guess:')
game.start
end
这将通过。问题是,如果你稍后决定让游戏开始说#嗨;嗨乔!",那么它就会失败。然后,您必须返回并修复您的规范,而实际上它已经符合规范。您需要一种机制让输出对没有行为的意外输入作出反应。这样,您可以获得预期的输出的特定示例,而不会在出现意外情况时失败。这似乎是非常基本的编程和单元测试断言,但是在RSpec中,它们以这种方式实现它,这对你和我来说似乎不太清楚。短语" null object"带有很多包袱,似乎并没有描述它在做什么,但它是一个空对象模式的实现(http://en.wikipedia.org/wiki/Null_Object_pattern)。