Search code examples
c#unit-testingunhandled-exception

Unit testing .NET events invocation


I have a static class that wraps around .NET events like UnhandledException and ProcessExit (of the CurrentAppDomain object), so that when the caller calls Initialize on the class, it subscribes my own handlers for these events, and later on the caller may add his own handler methods, using a dedicated API. (It it designed that way so I am able to control the order of handlers execution once the event is fired).

My question is: Is it possible to unit test such a class ?

For instance, I would like to know that when an unhandled exception is thrown, my private handler has executed. the problem is that when I throw unhandled exception, that will be the "result" of the test (correct me if I'm wrong). Same scenario will happen if I exit the process.

I was thinking that a possible solution might involve loading a new app domain, though I don't know if that's possible and how to technically approach that.


Solution

  • To test UnhandledException you can throw the exception in a new thread:

    [TestMethod]
    public void UnhandledTest()
    {
        using (var okEvent = new ManualResetEventSlim())
        using (var notOkEvent = new ManualResetEventSlim())
        {
            UnhandledExceptionEventHandler handler = (o, e) =>
                {
                    if (e.ExceptionObject is ApplicationException)
                        okEvent.Set();
                    else notOkEvent.Set();
                };
    
            AppDomain.CurrentDomain.UnhandledException += handler;
    
            var thread = new Thread(() => { throw new ApplicationException(); });
            thread.Start();
    
            var result = EventWaitHandle.WaitAny(new[] { notOkEvent.WaitHandle, okEvent.WaitHandle }, 10000);
            Assert.AreEqual(1, result);
    
            AppDomain.CurrentDomain.UnhandledException -= handler;
        }
    }
    

    This doesn't result in a failed test, because the test framework catches exceptions only on the thread that executes the test method.

    ProcessExit on the other hand will be raised when the current process is exiting, so it's quite likely that the test framework will have shut down by then. So you have to run the actual test code in a different process. From the unit test method, you will start a new process, it will run the meat of the test and communicate back to the unit test method in the original process the result of the test.

    The new process is simply a separate .exe project. What it does is attach to ProcessExit, stop itself, and in the ProcessExit handler check that everything is working in order, then it communicates the result back to the process running the unit test method.

    You could do the communication from the unit test project to the .exe project using the command line, and do the communication back using some sort of IPC, like temporary files or named events.