2009-10-21 67 views
4

問題是,如何測試事實,即在調用finalize時對象會分配資源。 爲類代碼:測試終結器和IDisposable

public class TestClass : IDisposable { 

    public bool HasBeenDisposed {get; private set; } 

    public void Dispose() { 
     HasBeenDisposed = true; 
    } 

    ~TestClass() { 
     Dispose(); 
    } 
} 

請注意,我不關心正確執行物/敲定剛纔我想找個首先測試它的方式。在這個階段,假設HasBeenDisposed將被設置爲true,如果Dispose/Finalize潔具被調用。

實際測試中,我寫的樣子:

[Test] 
public void IsCleanedUpOnGarbadgeCollection() { 
    var o = new TestClass(); 
    o.HasBeenDisposed.Should().Be.False(); 

    **var weak = new WeakReference(o, true); // true =Track after finalisation 
    o = null; // Make eligible for GC** 

    GC.Collect(0, GCCollectionMode.Forced); 
    GC.WaitForPendingFinalizers(); 


    **((TestClass)weak.Target)**.HasBeenDisposed.Should().Be.True(); 
} 

或者我更喜歡(的添加更新後)代碼:

[Test] 
public void IsCleanedUpOnGarbadgeCollection() { 
    WeakReference weak = null; 

    // Use action to isolate instance and make them eligible for GC 
    // Use WeakReference to track the object after finalisaiton 
    Action act =() = { 
     var o = new TestClass(); 
     o.HasBeenDisposed.Should().Be.False(); 
     weak = new WeakReference(o, true); // True=Track reference AFTER Finalize 
    }; 

    act(); 

    GC.Collect(0, GCCollectionMode.Forced); 
    GC.WaitForPendingFinalizers(); 

    // No access to o variable here which forces us to use WeakReference only to avoid error 
    ((TestClass)weak.Target).HasBeenDisposed.Should().Be.True(); 
} 

這個測試
與WeakReference的已更新失敗(PASSES AFTER UPDATE),但我觀察以下(修訂版):

  1. GC.WaitForPendingFinalizers()不掛起線程和定型例如在Ø,但前提是不能紮根。爲其分配NULL,並在完成後使用WeakReference獲取它。
  2. Finilize(析構函數)代碼在不包含該實例時在正確的點執行。

那麼測試這個的正確方法是什麼?我錯過了什麼?

我猜想這是一個變量Ø防止GC從收集它。
UPDATE:是的,這是問題。必須改用WeakReference。

+0

這正是我所需要的。你使用一個Action委託將我的代碼放到一個單獨的堆棧框架中,並允許我的單元測試正確地收集這些對象。 – NathanAW 2010-07-02 04:30:30

+0

感謝這個解決方案,它效果很好。對我來說,它只需將原始變量設置爲null即可在沒有委託的情況下工作。 (編輯:對necropost抱歉,沒有注意到日期) – amnesia 2017-02-23 21:20:15

回答

3

「我想這是防止GC收集它的變量o」。正確。堆棧中引用的存在意味着對象可以訪問,因此不符合收集(和定稿)的條件。

因爲一個對象直到沒有對它的引用纔會被最終確定,所以測試結束行爲可能會非常棘手。 (您需要對該對象進行引用才能對其進行斷言!)一種方法是間接執行該操作:讓對象在定稿過程中發送某種消息。但是這純粹爲了測試目的而扭曲了終結代碼。你也可以對該對象持有一個弱引用,這將使其有資格進行最終確定,並使其在終結者中重新生成自己 - 但又不想讓它在生產代碼中重新生成自己。

+0

我更改了代碼,以便在定稿後使用WeakReference跟蹤Target。用完整的代碼更新了問題。非常感謝給我這個想法。所有的事情都很簡單,如果你認爲簡單:) – 2009-10-21 01:52:47

0

爲什麼要收集對象,如果有本地引用它?

+0

是的。我的錯。我在最後一句中部分回答了我的問題。我應該發明一些其他的測試finiliser。 – 2009-10-21 01:32:26

0

內存分析器是測試泄漏的最合適方法。

我可以推薦.Net Memory Profiler。