嗯,我是一个红宝石新手,我正在尝试用RubyKoans学习,但我对这个测试感到困惑
def test_dice_values_should_change_between_rolls
48 dice = DiceSet.new
49 dice.roll(5)
50 first_time = dice.values
51
52 dice.roll(5)
53 second_time = dice.values
54
55 assert_not_equal first_time, second_time,
56 "Two rolls should not be equal"
57 end
这是DiceSet类
5 class DiceSet
6 attr_accessor :values
7 ··
8 def initialize
9 @values = []
10 end
11
12 def roll(times)
13 @values.clear
14 times.times do |x|
15 @values << ( 1 + rand(6))
16 end
17 end
18 ····
19 end
这里的事情是,每当我运行代码时,它总是生成完全相同的数字集,这就是输出。
Two rolls should not be equal. <[3, 2, 4, 1, 3]> expected to be != to <[3, 2, 4, 1, 3]>.
在测试我调用DiceSet.roll两次,对于那两次,我得到完全相同的“随机”数字集合,当他们被认为是不同的权利?我想我可能会创建另一个DiceSet实例以通过测试,但我猜测这不是测试的目标
答案 0 :(得分:6)
问题是DiceSet#values
返回对数组的引用,并且该数组在DiceSet对象的整个生命周期内保持不变。在DiceSet#roll
中清除该数组,然后添加新数字。由于对DiceSet#values
的两次调用都返回相同的引用,因此第一次滚动的结果将丢失,并且您的测试是将数组与其自身进行比较。
我不熟悉RubyKoans以及它们有什么要求,即如果DiceSet应该存储值等等。如果是,那么最直接的解决方案是使用两个DiceSets或使用Object#dup
存储测试返回对象的副本。
但是,请注意,即使代码运行正常,您的测试仍然很脆弱,因为总有两个连续卷可能会返回完全相同的数字。在这种特殊情况下,它相对较小但仍然非常存在。
答案 1 :(得分:1)
以下内容适用于此测试:
class DiceSet
attr_accessor :values
def roll (times)
@values = []
times.times do |x|
@values << ( 1 + rand(6) )
end
end
end
所以我们正在为每个卷创建新数组。
答案 2 :(得分:0)
最好使用attr_reader而不是attr_accessor(就像Ilya Tsuryev建议的那样)。因为您不希望客户端代码欺骗骰子。 并且使用rand(1..6)更具可读性。
class DiceSet
attr_reader :values
def roll(set_size)
@values = []
set_size.times { @values.push rand(1..6) }
end
end
答案 3 :(得分:-1)
每次使用一个新阵列将解决dominikh所指出的参考问题,但正如他所说的那样,并不能保证你连续2次掷骰都有不同的nos。在我的实现中,我记得最后一次抛出并循环,直到我得到一个不同的集合:
class DiceSet
attr_reader :values, :lastroll
def initialize
@values = []
@lastroll = []
end
def roll(n)
while @values == @lastroll
@values = Array.new(n) { |i| i = rand(6) + 1 }
end
@lastroll = @values
end
end