2011-12-06 127 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