私人方法' put'?在RSpec Book的Codebreaker示例中无法通过黄瓜测试

时间:2014-11-05 02:19:39

标签: ruby rspec cucumber

我跟随RSpec书,我无法通过黄瓜测试通过某个地点。我甚至试过在书中的源代码上运行黄瓜,它仍然没有通过。我不确定我是否使用了更新版本的黄瓜,但必须有办法让它通过!

当我到达程序应该开始一个新游戏的时候,我告诉那里有一个未定义的方法' puts'。为什么它未定义,我应该如何捕获Cucumber中的puts程序?在RSpec中运行测试以确保游戏使消息正常工作,不确定如何使其通过黄瓜。

(Cucumber版本1.3.17,Ruby版本2.1.2)

基本上,我有这些功能:

Feature: code-breaker starts game
As a code-breaker
I want to start a game
So that I can break the code
Scenario: start game
    Given I am not yet playing
    When I start a new game
    Then I should see "Welcome to Codebreaker!"
    And I should see "Enter guess:"

和这些步骤定义:

    class Output
      def messages
        @messages ||= []
      end
      def puts(message)
        messages << message
      end
    end
    def output
      @output ||= Output.new
    end

    Given /^I am not yet playing$/ do
    end

    When /^I start a new game$/ do
      game = Codebreaker::Game.new(output)
      game.start
    end

    Then /^I should see "([^"]*)"$/ do |message|
      output.messages.should include(message)
    end

和这个红宝石代码:

    module Codebreaker

        class Game

            def initialize(output)
                @output = output
            end

            def start
                @output.puts 'Welcome to Codebreaker!'
            end
        end
    end

我一直收到这个错误:

When I start a new game                     # features/step_definitions/codebreaker_steps.rb:16
  private method `puts' called for #<RSpec::Matchers::BuiltIn::Output:0x007fa4ea200ad0> (NoMethodError)

  ./lib/codebreaker/game.rb:10:in `start'
  ./features/step_definitions/codebreaker_steps.rb:18:in `/^I start a new game$/'
  features/codebreaker_starts_game.feature:7:in `When I start a new game'

如何解决这个问题,以便它传入黄瓜?

3 个答案:

答案 0 :(得分:6)

自从发布RSpec Book之后,有很多事情发生了变化,但是我通过用{:}替换你的code_break_steps.rb文件来实现它。

Given /^I am not yet playing$/ do
end

When /^I start a new game$/ do
  @messenger = StringIO.new
  game = Codebreaker::Game.new(@messenger)
  game.start
end

Then /^I should see "([^"]*)"$/ do |message|
  expect(@messenger.string.split("\n")).to include(message)
end

RSpec 3有一个你试图覆盖名为Output的类,这引起了太多混乱。我只是对此进行了简化,因此您的测试仍在与stdout一起互相讨论。

您可以在最后一行使用相同的should语法,但很快就会弃用它,以便更好地习惯我使用的expect语法。现在,如果这更令人困惑,你仍然可以使用:

@messenger.string.split("\n").should include(message)

答案 1 :(得分:1)

我现在正在关注这本书,并尝试了安东尼的技巧。但是我在书中稍后再次遇到麻烦(很可能是因为我是Rails的初学者并且无法将Anthony的技术翻译成另一个案例^^)。但无论如何,我发现了一种不干扰RSpec输出类的简单方法,但仍然没有从课程流程中转移太多:

  • 将项目Output类重命名为其他名称,例如OOutput
  • 并将所有output个变量更改为o_output

Etvoilà; - )

答案 2 :(得分:0)

我能够使该特定示例仅对同一个“ codebreaker_steps.rb”文件进行两次调整,因此您仍然可以按照本书的课程进行。您不必触摸类名,只需触摸其后的output()方法即可。

RSpec 3包含一个output()方法,当您尝试定义另一个output()方法时会导致冲突。因此,在了解了这一点之后,请按照本书的说明进行操作:

def output
 @output ||= Output.new
end

并将其重命名为:

def see_output #new
 @output ||= Output.new
end

(或命名对项目有意义的任何内容)

然后转到您的When()方法定义:

When /^I start a new game$/ do
 game = Codebreaker::Game.new(output)
 game.start
end

并将第二行更新为:

When ("I start a new game") do
 game = Codebreaker::Game.new(see_output) #new
 game.start
end