4

I've got some tests and they rely heavily on some shared code that I can't modify. This shared code throws an exception sometimes and I want to be able to handle all uncaught instances of this exception without wrapping every call to the shared code in a try catch (there are years of tests here).

I also want to be able to re-throw the exceptions that aren't of the type that I'm looking for.

I've tried

public void init() 
{
    AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
}
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
    Logger.Info("Caught exception");
    throw (Exception)e.ExceptionObject;
}

But it appears that the stock unit test framework (Microsoft.VisualStudio.QualityTools.UnitTestsFramework) is doing something with the AppDomain and preventing me from replacing its UnhandledException handler or I'm simply not understanding how the unit test framework handles AppDomains (highly likely).

Anyone have any suggestions?

Reuben Tanner
  • 5,229
  • 3
  • 31
  • 46
  • If the third-party code throws an unhandled exception during your test, then surely that exception should be allowed to affect the outcome of your test. Why do you want to handle that exception? – John Saunders Apr 30 '15 at 22:53
  • 1
    Are these exceptions occurring during the test itself? If so, most unit test frameworks will catch the exception as part of running the test (to report the exception), before it ever gets to an UnhandledException handler. – Dan Bryant Apr 30 '15 at 22:54
  • @JohnSaunders, I do understand that in most circumstances I wouldn't want to handle this exception but there's a very involved set up procedure with these tests and the cause likely lies in the set up. If I can handle the exception, then I can re-set up the environment and perhaps salvage the test. I know this is smelly but it comes with the territory and the complexity of them. – Reuben Tanner Apr 30 '15 at 23:08
  • And for future viewers of this question, when I say that the set up procedure is "very involved" for these tests, I mean _very_ involved: booting up virtualized processors, loading them with test collateral, beginning several, interacting processes...they're certainly above and beyond unit tests but we use the framework to run them. – Reuben Tanner May 01 '15 at 00:20

2 Answers2

2

Try attaching to the AppDomain.CurrentDomain.FirstChanceException event. Per Microsoft's documentation:

Occurs when an exception is thrown in managed code, before the runtime searches the call stack for an exception handler in the application domain.

In other words, you can catch it before the Unit Test Framework does. More info here.

321_contact
  • 117
  • 1
  • 6
1

Too bad there has to be a workaround for this, but below is mine. We use unhandled exception handler in the application, which was triggered by some error. Unfortunately the unhandled exception was swallowed by the test framework during unit testing.

using System;
using Xunit;
using System.Threading;

public class MyTests : IDisposable
{
    private UnhandledExceptionEventArgs _unhandledException = null;
    public MyTests()
    {
        AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
    }

    public void Dispose()
    {
        Assert.Null(_unhandledException);
    }

    private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        _unhandledException = e;
    }

    //Example from : https://github.com/xunit/xunit/issues/157
    [Fact]
    public void TestExceptionInBackgroundThread()
    {
        Thread t = new Thread(() =>
        {
            throw new InvalidOperationException();
        });
        t.Start();
        t.Join();
    }
}

output

RuudSieb
  • 523
  • 5
  • 13