I have a helper-class for my unit-tests that share a reference to an COM-object in memory:
public class UnitTestGeometryProvider
{
public static readonly IGeometry Geometry = Deserialize();
}
The geometry is deserialized from a Xml file which is stored as a resource file and appended to the project. Afterwards it is wrapped into a COM object:
public static IGeometry Deserialize()
{
return (IGeometry) new XMLSerializerClass().LoadFromString(myXDoc.OuterXml, null, null);
}
Now I have two test-methods that use the geometry stored within this class:
[TestClass()]
public class MyTest
{
[TestMethod()]
public void FirstTest()
{
var p = UnitTestGeometryProvider.Geometry;
}
[TestMethod()]
public void SecondTest()
{
var p = UnitTestGeometryProvider.Geometry;
}
}
When running the second one I get a COMException:
COM object that has been separated from its underlying RCW cannot be used
I wonder why the reference to the COM-object is released as it is marked static
in UnitTestGeometryProvider
and I do not explicitly release it. So even if the managed resource to the instance would go out of scope (which is does not at it is static), the underlying COM object should go away only when all my tests finished or more general when the application terminates, or do I miss anything?
I am using ArcObjects and Visual NUnit.
Due to the comments by Hans Passant I found the actual problem.
Obviously the Visual-NUnit-Framework decides to create a separate thread for every test. Thus whenever I create a COM-object - be it static or not - this object lives on this single thread and cannot be used in another one. If the thread dies also does the COM-object or to be more precise the reference to it. This leads to the GC kicking in throwing the COM-object away as no more managed references to it exist within that thread.
The solution is pretty straitforward: I changed the static field to instance-members and created an instance-member of type UnitTestGeometryProvider
within my test-class. Thus a new provider is generated by every test.
However this solution is quite annoying because the Geometry
-property has to be initialized and therefor the Deserialize
-method runs for every test instead of only once for all tests.
I don´t know if there is a thread-safe solution to not kill the reference to the COM-object when the first thread that intialized it dies.