I am running into a NullReferenceException when trying to validate a method in an abstract class that aborts a background thread. I want to verify that, in addition to other things that happen in the method, the background thread is aborted. This sample code is a simplified version of the real code that focuses on aborting the thread.
public abstract class Foo
{
public static void KillTime()
{
try
{
for (int i = 0; i < 10000000; i++)
{
Thread.Sleep(1);
}
}
catch
{
Thread.Sleep(100);
}
}
public Thread MyThread { get; set; }
public void StartThread()
{
MyThread = new Thread(new ThreadStart(RunStuff));
MyThread.Name = "Thread RunStuff";
MyThread.Start();
}
public void AbortThread()
{
MyThread.Abort();
}
public void RunStuff()
{
KillTime();
}
}
Here is the unit test that is a simplified form of my actual unit test.
[TestMethod]
public void AbortThreadTest()
{
Foo fakeFoo = Isolate.Fake.Instance<Foo>(Members.CallOriginal);
//Isolate.WhenCalled(() => fakeFoo.RunStuff()).DoInstead(context => Foo.KillTime());
fakeFoo.StartThread();
Thread.Sleep(50);
fakeFoo.AbortThread();
Assert.AreEqual<ThreadState>(ThreadState.AbortRequested | ThreadState.WaitSleepJoin, fakeFoo.MyThread.ThreadState,
"The thread has not been aborted");
Assert.IsTrue(fakeFoo.MyThread.Join(500), "The thread did not finish aborting in time");
}
As listed above, the unit test above passes. This indicates that the KillTime method is not a problem. However, if the commented line is uncommented (as in the real unit test), then the test is aborted and the test run reports the following error:
One of the background threads threw exception: System.NullReferenceException: Object reference not set to an instance of an object.
at du.Invoke(Object[] A_0, Object A_1)
at ad.a(DynamicReturnValue A_0, Object A_1, Object[] A_2, Object A_3)
at ad.a(DynamicReturnValue A_0, Object A_1, Object[] A_2, Type A_3, Object A_4)
at ad.a(Object A_0, Object[] A_1, Type A_2, Scope A_3, Int32 A_4, Object A_5, Type A_6)
at bi.a(String A_0, Object[] A_1, Object A_2, Object A_3, String A_4, Type A_5)
at b2.a(String A_0, Object A_1, MethodBase A_2, Object[] A_3, Object A_4, String A_5, bi A_6)
at b2.b(Object A_0, String A_1, String A_2, MethodBase A_3, Object[] A_4, Object A_5)
at TypeMock.MockManager.a(String A_0, String A_1, Object A_2, Object A_3, Boolean A_4, Object[] A_5)
at TypeMock.InternalMockManager.getReturn(Object that, String typeName, String methodName, Object methodParameters, Boolean isInjected)
at TestProject1.Foo.RunStuff() in ...TestProject1UnitTest1.cs:line 115
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.runTryCode(Object userData)
at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
Test host process exited unexpectedly.
If I comment the last Assert out that does the Join, then the test passes, but I still get a test run error that only reports the last line in the error above: "Test host process exited unexpectedly."
The actual RunStuff method is private in my abstract class; making it public (like in the code above) did not make a difference.
Also, I tried making the Foo class above a concrete class (unlike my actual class which is abstract - hence, the need to create a fake instance) and still encountered the same problems. However, if I made Foo a concrete class and created a real instance (avoiding Isolator altogether), then the test passed and the test run did not report any errors.
I am looking for any ideas as to what is wrong with the test or suggestions on alternate approaches to testing that the thread gets aborted.
Thanks,
Brian