我正在做一个二十一点游戏。我的游戏对象包含一个甲板对象,在甲板达到一定的穿透水平后进行洗牌。我的许多方法都依赖于这个deck对象。我没有看到任何理由通过setter方法访问deck对象。我在Game类上测试方法时遇到了麻烦,因为它们依赖于甲板的顺序,这是随机的。
例如,我有deal_hand方法。
def deal_hand(player)
reset_deck if @deck.size < 2
player.hands.push(Hand.new(*@deck.pop(2)))
end
我应该如何测试这样的方法?我想我可以手动创建一个在@deck实例变量中使用的Deck对象。不幸的是,我无法设置实例变量,我真的不想添加一个setter,因为除了测试之外没有理由可以“设置”。我应该从我的测试文件中修补该类并添加一个setter吗?
顺便说一句 - 我主要是编写脚本 - 我决定在这个项目失控之后我需要开始编写测试。是否存在“测试模式”的规范资源?
编辑:
我正在使用MiniTest,它支持存根/模拟。虽然据我所知,它只允许您为模拟对象上的方法调用设置预期的返回值。如果我做了一个模拟牌组,实际的牌组对象也取决于内部阵列。调用deck的代码都没有直接访问数组。
答案 0 :(得分:2)
使用模拟库。 RSpec是用一个构建的,但我不喜欢它,所以我会告诉你Surrogate可能是什么样子,我写的那个:
class Deck
def pop(n) end
def reset() end
def size() end
end
class Game
def initialize(deck)
@deck = deck
end
def deal_hand(player)
reset_deck if @deck.size < 2
player.hands.push(Hand.new(*@deck.pop(2)))
end
def reset_deck
@deck.reset
end
end
Hand = Struct.new :card1, :card2
class Player
def hands
@hands ||= []
end
end
require 'surrogate/rspec'
class MockDeck
Surrogate.endow self
define(:reset)
define(:pop) { |n| n.times.to_a }
define(:size) { 1 }
end
describe Game, 'deal_hand' do
let(:deck) { MockDeck.new }
let(:player) { Player.new }
let(:game) { Game.new deck }
it 'resets the deck if there are less than 2 cards' do
deck.will_have_size 2 # set the return value of deck.size
game.deal_hand player
deck.was_not told_to :reset # assert what happened to the deck
deck.will_have_size 1
game.deal_hand player
deck.was told_to :reset
end
it 'deals the top 2 cards to the player' do
deck.will_pop [:card1, :card2]
game.deal_hand player
deck.was told_to(:pop).with(2)
player.hands.last.should == Hand.new(:card1, :card2)
end
end
describe Deck do
it 'is substitutable for the mock' do
# because we use the mock in tests
# we want to make sure its interface matches the real deck
Deck.should substitute_for MockDeck
end
end
答案 1 :(得分:1)
您是否考虑过使用mocha?
这将允许您存根或模拟Deck以确保它具有用于测试运行的预期卡片。
答案 2 :(得分:1)
在测试中使用方法instance_variable_set,它是对象上的ruby方法。
所以我假设你的方法在Game类中,所以如果你正在设置像
那样的话@test_deck = something_that_sets_up_state_of_test_deck
@game = Game.new
@game.instance_variable_set(:deck, @test_deck
这将在Game中设置您的实例变量,而无需显式构建attr_accessible或getter和setter。