DUnit has an option to use JCL to generate stack traces. The idea is that, whenever there’s an exception or a test failure, DUnit will show a stack trace right along with the failure message. The only problem is, it doesn’t work.
There’s no problem getting stack traces for unexpected exceptions. This is really useful; you get the address, unit name, method name, and even the line number of the line that threw an exception, together with the call stack that led to that code getting called. Immensely useful.
The problem is, you don’t get the same thing for test failures — even though
CheckEquals, and even DUnitLite’s
Specify.That, operate by throwing exceptions (they’ve got their own exception class,
ETestFailure). You should be able to get a stack trace that shows the exact line of code that contained the failing assertion. In fact, we’re using older versions of DUnit and JCL at work, and we get stack traces just fine.
Unfortunately, stack traces for test failures are broken by default in the latest versions of DUnit and JCL. But there’s hope — notice that I said “by default”. Below, I’ll tell you how to fix that default.
Enabling DUnit stack tracing
First of all, here’s how to get DUnit to show stack traces in the first place.
JCL\Windows directories to your project’s search path.
Then make the following changes in Project > Options:
- On the Directories/Conditionals page, set “Conditional defines” to:
- On the Linker page, set “Map file” to “Detailed”.
Now write a test that throws an unexpected exception, compile, and run. Here’s a contrived example, but it’ll give you an idea of what it looks like:
Enabing stack tracing for test failures
We don’t get unexpected exceptions in our tests very often. More often, it’s test failures. And when we have more than one assertion in the same test (not the ideal, but it happens a lot), sometimes it’s hard to know which assertion failed. Or rather, it’s always easy to know, if you have stack traces.
The problem is with JCL’s exclusion list. The latest version of JCL keeps a configurable list of exception types that it shouldn’t generate stack traces for. Seems like a reasonable feature. But the JCL and DUnit teams made three important design decisions, at various points in time:
- JCL’s exclusion list, by default, contains one class:
- JCL ignores not just the classes in the exclusion list, but any of their descendant classes as well.
ETestFailuredescends from… yep, you guessed it,
Put all three together, and stuff doesn’t work.
But, all that said, it’s easy to work around. Just add the following code to your project file, before you call one of the
uses ..., JclDebug, ...; begin ... JclDebug.RemoveIgnoredException(EAbort); ... end.
And bask in the goodness that is stack traces.