0

我第一次使用 RSpec 来创建一个包含 Card、Deck、Hand、Player 和 Game 类的扑克游戏。我已经完成了卡片、套牌和手牌测试/课程,我目前正在编写玩家测试/课程。随着依赖项的增长,依赖模拟/存根变得更加困难,并且我遇到了一个问题,即我的 Player#discard 方法测试抛出错误,因为 RSpec 抛出此错误:

1) Player#discard discards the chosen card
   Failure/Error: player.discard
      Double "hand" received unexpected message :delete_if with (no args)
    # ./lib/player.rb:19:in `block in discard'
    # ./lib/player.rb:18:in `each'
    # ./lib/player.rb:18:in `discard'
    # ./spec/player_spec.rb:34:in `block (3 levels) in <top (required)>'

我是 RSpec 的新手,不太确定我做错了什么。任何有关避免在我的规范中使用实际类对象以使其通过的方法的帮助和建议将不胜感激。到目前为止,这是我的 player_spec 和 Player 课程。

./spec/player_spec.rb

require 'rspec'
require 'player'

describe Player do
  subject(:player) { Player.new }

  its(:hand) { double("hand", :cards => []) }
  its(:pot)  { should eq 1000 }

  let(:ace_spades)    { double("card", :suit => :spades, :value => :ace) }
  let(:ace_clubs)     { double("card", :suit => :clubs, :value => :ace) }
  let(:king_spades)   { double("card", :suit => :spades, :value => :king) }
  let(:king_clubs)    { double("card", :suit => :clubs, :value => :king) }
  let(:queen_spades)  { double("card", :suit => :spades, :value => :queen) }
  let(:queen_clubs)   { double("card", :suit => :clubs, :value => :queen) }
  let(:jack_spades)   { double("card", :suit => :spades, :value => :jack) }
  let(:jack_clubs)    { double("card", :suit => :clubs, :value => :jack) }
  let(:ten_spades)    { double("card", :suit => :spades, :value => :ten) }
  let(:ten_clubs)     { double("card", :suit => :clubs, :value => :ten) }
  let(:nine_spades)   { double("card", :suit => :spades, :value => :nine) }
  let(:nine_hearts)   { double("card", :suit => :hearts, :value => :nine) }
  let(:nine_clubs)    { double("card", :suit => :clubs, :value => :nine) }
  let(:nine_diamonds) { double("card", :suit => :diamonds, :value => :nine) }

  let(:discard_hand)  do 
    double("hand", :cards => [nine_clubs, ace_spades, nine_hearts, ten_clubs, ten_spades])
  end
  let(:discard_input) { ["A","S"] }

  describe "#discard" do
    it "discards the chosen card" do
      player.hand.stub(:cards).and_return(discard_hand)
      player.stub(:get_input).and_return(discard_input)
      player.discard
      expect(player.hand.cards).to eq([nine_clubs, nine_hearts, ten_clubs, ten_spades])
    end
  end
end

./lib/player.rb

class Player
  INPUT_VALUES = { "2" => :deuce, "3" => :three, "4" => :four, 
               "5" => :five, "6" => :six, "7" => :seven, 
               "8" => :eight, "9" => :nine, "10" => :ten, 
               "J" => :jack, "Q" => :queen, "K" => :king, "A" => :ace }
  INPUT_SUITS  = { "S" => :spades, "H" => :hearts, "C" => :clubs, "D" => :diamonds }

  attr_accessor :pot, :hand

  def initialize
    @pot  = 1000
    @hand = Hand.new
  end

  def discard
    discards = get_input("Which card(s) would you like to discard?:")

    discards.each do |discard|
      self.hand.cards.delete_if do |card| 
        card.value == discard[0] && card.suit == discard[1]
      end
   end
 end

private

  def get_input(prompt)
    puts prompt
    input = gets.chomp
    parse_input(input)
  end

  def parse_input(input)
    value = input.scan(/^(?:[2-9]|10|[jqkaJQKA])/)
    suit = input.scan(/[shdcSHDC]$/)
    raise "Invalid Input" if values.empty? || suit.empty?

    (value[0].match(/[jqkaJQKA]/)) ? value[0].upcase! : value.map!(&:to_i)
    suit[0].upcase!

    value = INPUT_VALUES[value[0]]
    suit  = INPUT_SUITS[suit[0]]

    [value, suit]
  end
end
4

1 回答 1

1

你得到了你得到的错误,因为你调用的代码(即discard)正在调用delete_if你的一个双打,你没有设置一个允许这样做的期望。您应该签出stub_chain作为实现此目的的一种手段。

不过,更一般地说,我认为您遇到了麻烦,因为您要求Playerdiscard 方法通过直接对卡片数组进行操作而不是委托discardHand. 如果您可以简化代码,它将简化您的测试。

于 2013-11-02T19:36:19.497 回答