I have the following class which is a decorator for an IDisposable
object (I have omitted the stuff it adds) which itself implements IDisposable
using
It's not easy to test finalization, but it can be easier to test if an object is a subject to garbage collection.
This can be done with a weak references.
In a test, it's important to for the local variables to run out of scope before calling GC.Collect(). The easiest way to make sure is a function scope.
class Stuff
{
~Stuff()
{
}
}
WeakReference CreateWithWeakReference(Func factory)
{
return new WeakReference(factory());
}
[Test]
public void TestEverythingOutOfScopeIsReleased()
{
var tracked = new List();
var referer = new List();
tracked.Add(CreateWithWeakReference(() => { var stuff = new Stuff(); referer.Add(stuff); return stuff; }));
// Run some code that is expected to release the references
referer.Clear();
GC.Collect();
Assert.IsFalse(tracked.Any(o => o.IsAlive), "All objects should have been released");
}
[Test]
public void TestLocalVariableIsStillInScope()
{
var tracked = new List();
var referer = new List();
for (var i = 0; i < 10; i++)
{
var stuff = new Stuff();
tracked.Add(CreateWithWeakReference(() => { referer.Add(stuff); return stuff; }));
}
// Run some code that is expected to release the references
referer.Clear();
GC.Collect();
// Following holds because of the stuff variable is still on stack!
Assert.IsTrue(tracked.Count(o => o.IsAlive) == 1, "Should still have a reference to the last one from the for loop");
}