问题是我如何测试对象在调用finalize时处理资源的事实。 该类的代码:
public class TestClass : IDisposable {
public bool HasBeenDisposed {get; private set; }
public void Dispose() {
HasBeenDisposed = true;
}
~TestClass() {
Dispose();
}
}
请注意我现在不关心Dispose / Finalize的正确实现,因为我想先找到测试它的方法。在此阶段,如果调用Dispose / Finalize ware,则将 HasBeenDisposed 设置为true就足够了。
我写的实际测试看起来像:
更新弱势:
[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();
}
此测试失败(更新后通过),但我观察到以下情况(更新):
那么测试这个的正确方法是什么。我错过了什么?
我认为变量 o 会阻止GC收集它。
更新:是的,这是问题所在。不得不改用WeakReference。
答案 0 :(得分:3)
“我想这是阻止GC收集它的变量o。”正确。堆栈上存在引用意味着该对象是可访问的,因此不符合收集(和最终化)的条件。
因为在没有引用对象之前不会最终确定对象,所以测试终结行为可能会很棘手。 (您需要对该对象的引用才能对其进行断言!)一种方法是间接执行:让对象在最终确定期间发送某种消息。但这会使完成代码完全出于测试目的而扭曲。您还可以对该对象进行弱引用,这将使其有资格进行最终化,并使其在终结器中自我复活 - 但同样,您不希望它在生产代码中恢复自身。
答案 1 :(得分:0)
如果有对象的本地引用,为什么会收集该对象?
答案 2 :(得分:0)
内存分析器是测试泄漏的最合适方法。
我可以推荐.Net Memory Profiler。