Unit testing with asserts: Why is assertHandler required to throw?
Nick Sabalausky
a at a.a
Sun Jan 31 12:58:20 PST 2010
"Trip Volpe" <mraccident at gmail.com> wrote in message
news:hk4pql$1ehf$1 at digitalmars.com...
>I recently began porting an existing C++ project of mine (a
>compiler/interpreter for a dynamic language) to D. In the process I found
>that the built-in unit testing support, while an awesome concept, was a
>little bit sparse. In particular, assert() is fairly useless for unit
>tests, since it throws on a failure and prevents all subsequent tests from
>running.
>
> Unfortunately, it's the only facility that seems to give you access to the
> current file and line number, very important bits of info for unit tests
> in a any non-trivial project. I was contemplating just abandoning D and
> sticking with C++ and Googletest, but after doing a bit of digging through
> the source, I found setAssertHandler() in core.exception. Perfect! I could
> use my own assert handler that just records the error and allows future
> asserts to still be reached. So I wrote it up and gave it a try, but
> pretty quickly started getting access violation errors.
>
> I did a bit of searching, and found a bug report on the issue:
>
> http://d.puremagic.com/issues/show_bug.cgi?id=3208
>
> In the comments it's indicated that this is intentional, that the compiler
> expects the assertion handler to throw. So I guess I have a few questions:
>
> 1. Why is this the expected behavior? It seems to me that there are
> relatively few useful things you can do with a custom assert handler
> unless it is possible to refrain from throwing.
>
> 2. Is this going to be fixed any time soon? It seems fairly important to
> me; it really kills the value of built-in unit tests to be forced to
> choose between not having any line number information and being able to
> recognize only one assert failure per test run(!!!).
>
> 3. Are there any current workarounds for the problem? I could just use my
> own assertion function, but 1) I can't call it "assert" because that's a
> reserved word, and 2) most importantly, it won't have any way of
> indicating in its diagnostic output which source line the failure occurred
> on. In C++, of course, I could use preprocessor macros to do that, but D
> omits a preprocessor (for very good reasons). Unfortunately, this seems
> like a case where D hasn't provided replacement functionality.
>
> But maybe there's a sneaky fix I haven't thought of? I also found
> Runtime.moduleUnitTester() in core.runtime, which is very useful in
> itself, but provides an _almost_ useful improvement: I can catch the
> AssertErrors on a module-by-module basis, which would at least allow the
> unit tests for all modules to be run regardless of a failure in one of
> them. However, a single module could easily have dozens of tests in it,
> each of which could contain many individual asserts. Stopping the test
> early because one assert failed makes no sense.
>
> It would be _almost_ acceptable to at least be sure of running all the
> tests in each module; is there any way to poke inside or otherwise
> override ModuleInfo's unitTest() function?
>
>
> Thanks in advance for any advice or comments! D is a completely awesome
> language, but I found this issue a bit strange.
The deferAssert module (possible name change and other API improvements
pending) of my SemiTwist D Tools library (
http://www.dsource.org/projects/semitwist ) is designed to get around those
problems. Here's a sample app with it's own output in the comments at the
bottom:
http://www.dsource.org/projects/semitwist/browser/trunk/src/semitwist/apps/tests/deferAssertTest/main.d
And the closest thing I have to an API reference at this point:
http://www.dsource.org/projects/semitwist/browser/trunk/src/semitwist/util/deferAssert.d
(BTW, contrary to the names, deferAssert and deferEnsure don't actually
defer anything other than throwing the fatal assert exception)
More information about the Digitalmars-d
mailing list