views:

551

answers:

6

When testing with Visual Studio Team Test unhandled exceptions in tests are caught and reported in the results. So I was kind of surprised to see the test hosting process (VSTestHost.exe) crash and showing the system crash dialog.

Upon further investigation this crash was an unhandled exception raised in another thread (more directly, it was an async socket callback). And indeed something like this crashes the hosting process:

[TestMethod]
void Test()
{
    new Thread(() => { throw new Exception(); }).Start();
}

Any advices what I should do there?

  • Should I just live with it, saying any code distributed/checked-in should be tested at least once anyway, and so such things most likely will be caught?
  • Should I try to install a global exception handler and check its status in every tear-down method?
  • Or maybe there are already exists stuff helping with this?
A: 

You could try setting AppDomain.CurrentDomain.UnhandledException and see if that works? I don't know how that interacts with the VS test harness thought

Orion Edwards
A: 

Generally I try to avoid starting threads in unit tests by injecting a thread provider that, during unit tests, doesn't actually provide a thread, but rather executes syncronously.

Of course, with that approach you can't test any kind of potential contention, or two real code paths running in parallel, but there is a good argument to be made that such a test isn't really a unit test.

When you do test two simultaneous threads, then you need a thread provider which catches exceptions at the end of the the thread and reports them as failures.

Yishai
This works fine when you explicitly control the threads (and don't want to test the actual threading).But the code that brought me to this question uses the new asynchronous socket implementation (SocketAsyncEventArgs) which runs delegates on the internal thread pool which I cannot control.
gix
A: 

A couple of ideas:

  • Use BackgroundWorker to do the unit test work. BackgroundWorker will automatically catch unhandled exceptions and report them in Error property of RunWorkerCompletedEventArgs. However you will need a way to block the unit test thread until BackgroundWorker completes the work.
  • This one is a not good option by itself and may not even be suitable for your testing goals. Nonetheless I wanted to mention. You can go back to how unhandled exceptions from other threads were treated in .NET 1.0 and 1.1 by using legacyUnhandledExceptionPolicy. Prior to .NET 2.0, unhandled exceptions from threads were quietly ignored. However, in .NET 2.0, they actually cause the application to terminate. legacyUnhandledExceptionPolicy setting allows you to have pre .NET 2.0 behavior.
Mehmet Aras
+1  A: 

You can use a Global Exception handler to catch all of the uncaught exception in the AppDomain:

AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new EventHandler(UnhandledExceptionHandler);

I think it would work for exceptions thrown from other threads as well

Dror Helper
+1  A: 

What I can say from the realm of C++ (if the knowledge can be translated) is that any exception thrown in a given thread can only be caught in that thread. If your main application launches three other threads, then you have to catch exceptions from each of the (now 4) threads independently. There is no way to implement a "global" exception handler in threaded code. This has to do with how threads (and processes) are implemented in the OS.

But like I said, I don't know how closely that logic translates to C#, because it runs on top of a VM like Java.

Chris
+1  A: 

Having more than one thread in your tests doesn't sound very unity to me. Is there anything about the logic that is under test that dictates that there must be several threads? Really?

Or is it the case that there are some collaborators of the code under test that happens to be multithreaded (like the socket)? If that is the case, you really should substitute those collaborators with some kind of test doubles (mocks, stubs or whatever). The added benefit of using test doubles is that you can control their behaviour and responses easier than you could if they were the real thing.

KaptajnKold