2011-12-06 82 views
1

我是一个新手,红宝石和IM努力学习与RubyKoans但我得到stucked与这个测试相同的随机数红宝石

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]>. 
测试IM调用DiceSet.roll两次,并为那些两次我得到完全相同的一组“随机”数

时,他们supossed是diferent吧?我想我可能会创建DiceSet的另一个实例,以通过测试,但我猜测这不是测试的目标

+1

对于这个工作,你需要做的'FIRST_TIME = Array.new(dice.values)'和'second_time = Array.new(dice.values)' –

+0

我与你古斯塔沃。我想节省内存并重复使用相同的Array。不幸的是,koans的设计者忘记了等式首先检查引用,然后检查实例变量。解决这个引用问题的一个可能的方法是将'first_time = dice.values'改为'first_time = dice.values.clone'。但是这并不能解决这样一个事实,即无论如何这次测试都会失败。 –

回答

6

问题是,DiceSet#values返回一个数组的引用,该数组保持不变在DiceSet对象的整个生命周期中。在DiceSet#roll您清除该数组,然后添加新的数字。由于对DiceSet#values的这两个调用都返回相同的参考,所以第一次滚动的结果将丢失,并且您的测试正在将该数组与自身进行比较。

我不熟悉的RubyKoans和他们有什么要求,也就是说,如果你DiceSet应该存储值等。如果是这样,那么最简单的解决方法是使用两个DiceSets或使用Object#dup来存储测试返回的对象的副本。

但是,请注意,即使正确运行代码,您的测试仍然很脆弱,因为始终有可能连续两次滚动返回完全相同的数字。在这个特殊情况下,它相对较小,但仍然非常存在。

+0

这些值每次都会被清除,但在每次滚动后的测试中,值都存储在另一个变量中。没有问题。 –

+2

不好意思?数字被存储在'@ values'中,并且他使用属性读取器'#values'来获取该数组。 'first_time'和'second_time'指向**完全相同的**数组。 –

+0

我的不好...我忽视了。 –

1

下应该为这个测试工作:

class DiceSet 
    attr_accessor :values 

    def roll (times) 
    @values = [] 
    times.times do |x| 
     @values << (1 + rand(6)) 
    end 
    end 
end 

所以我们创造了每卷的新阵列。

-1

每次使用一个新的数组将会解决dominikh指出的参考问题,但是正确地说,并不能保证你连续两次使用不同的数组。我在执行我记得上次遥,环周围,直到我得到不同:

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 
+0

这使得你的结果稍微随机。测试被破坏(对于两个结果集相同的不太可能的情况),您不应该为了解决这个问题而破坏代码,您应该修复测试。 –

0

最好是改用attr_reader attr_accessor的(如伊利亚Tsuryev建议)。因为你不希望客户端代码欺骗骰子。 使用rand(1..6)更具可读性。

class DiceSet 
    attr_reader :values 

    def roll(set_size) 
    @values = [] 
    set_size.times { @values.push rand(1..6) } 
    end 
end