我第一次使用 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