2011-11-16 56 views
4

您將如何測試具有一些併發功能的Ruby代碼?例如,讓我們假設我有一個預計可以防止死鎖的同步機制。有沒有一種可行的方法來測試它的真正作用?可以控制纖維的執行是前進的方向嗎?測試併發特性

+0

即使在社區比Ruby社區更注重併發性的語言中,這仍是一個難題。 http://stackoverflow.com/questions/12159/how-should-i-unit-test-threaded-code –

+0

任何機會,你可以發佈一些代碼,甚至僞代碼E?這很難一般地回答,並且很難知道您希望測試的代碼的哪些方面。 – davetron5000

回答

1

我需要確保我編寫的gem(redis-native_hash)可以處理對同一個Redis散列的併發寫入,檢測競爭條件並優雅地恢復。我發現爲了測試這個,我根本不需要使用線程。

it "should respect changes made since last read from redis" do 
    concurrent_edit = Redis::NativeHash.find :test => @hash.key 
    concurrent_edit["foo"] = "race value" 
    concurrent_edit.save 
    @hash["yin"] = "yang" 
    @hash["foo"] = "bad value" 
    @hash.save 
    hash = Redis::NativeHash.find :test => @hash.key 
    hash["foo"].should == "race value" 
    hash["yin"].should == "yang" 
end 

在此測試情況下,我剛纔實例代表Redis的哈希值的同時編輯另一個對象,有它做出改變,然後確定保存指向相同的散列已經存在的對象尊重這些變化。

並非所有涉及併發的問題都可以在沒有使用併發性的情況下進行測試,但在這種情況下是可行的。您可能想嘗試尋找類似的東西來測試您的併發解決方案。如果可能的話,它肯定是更容易的路線。

+0

我明白你的觀點。對於特定情況,這是一個優雅的解決方法。 – PJK

1

記錄爲Rails3中先進的使用場景這絕對是一個棘手的問題。我開始使用線程編寫我的測試,並意識到他們的方式我測試的代碼已經實現,我需要進程ID(PID)實際上是不同的。線程使用與啓動線程的進程相同的PID運行。學過的知識。

就在那時,我開始探索叉子,並遇到了這個堆棧溢出線程,並與fork_break一起玩。非常酷,並且易於設置。儘管我不需要爲我所做的工作提供斷點,但我只是想讓進程同時運行,使用斷點在未來可能會非常有用。我遇到的問題是我不斷收到EOFError,我不知道爲什麼。所以我開始實現自己的分叉,而不是通過fork_break,並發現在被測代碼中發生異常。可悲的是堆棧跟蹤由EOFError對我隱藏,雖然我明白,子進程突然結束,這是怎麼回事。

我遇到的下一個問題是DatabaseCleaner。不管使用哪種策略(截斷或事務),子進程的數據在子進程完成時被截斷/回滾,因此子進程插入的數據消失了,父​​進程無法選擇並驗證它是正確的。

在我的腦海裏敲了一下,並嘗試了許多其他不成功的東西之後,我碰到了這個帖子http://makandracards.com/makandra/556-test-concurrent-ruby-code,這幾乎就是我已經在做的事情,只有一點點補充。調用「Process.exit!」在叉子的盡頭。我最好的猜測(基於我對分叉的相當有限的理解)是,這會導致進程突然結束,以至於當子進程結束時它完全繞過任何類型的數據庫清理。所以我的父進程,實際測試,可以繼續並驗證它需要驗證的數據。然後,在正常的測試掛鉤(在本例中爲黃瓜,但也可以很容易地rspec)期間,數據庫清理器會像通常進行測試一樣啓動並清理數據。

所以,只是想我會分享一些我自己的經驗教訓,在這個討論如何測試併發功能。