Review: A new stab at a potential std.unittests
Jonathan M Davis
jmdavisProg at gmx.com
Sat Nov 20 16:37:10 PST 2010
On Saturday 20 November 2010 10:16:55 Lutger Blijdestijn wrote:
> I'm not particularly fond of this interface and think that a solution with
> a delegate / lazy or alias template parameter would be more convenient.
> However, until we have ast macros I do see the added value in this
> approach.
>
> Some remarks about the api, not a proper review of the code itself:
>
> - core.exception and std.string must be imported to use the module,
> relevant symbols should be selectively and publicy imported instead.
I hadn't thought of that. Good idea.
> - exception would be better abbreviated as ex instead of exc, I believe
> this is more conventional. (assertExThrown instead of assertExcThrown)
I'll think about it. I don't think that I've often seen it abbreviated at all.
But if Ex really is more common, then that would be better.
> - assertExcThrown should fail if an exception is thrown that is not T or a
> subclass of T. (catch and throw AssertError)
It currently catches the exact exception (well, throwable) that you tell it to.
The others are let through exactly like they would be with an assert. It also
means that you get to see exactly what the erroneous exception was so that you
can deal with it. An AssertError would be less informative, maybe even
misleading. You get an AssertError because it didn't throw any exception,
whereas you get the wrong exception if it threw the wrong one.
I suppose that I could see an argument that because it didn't throw that exact
exception, it should throw an AssertError, but I think that it's worse, because
you can't see what the unexpected exception was. It would be less helpful in
debugging rather than more.
> - assertEqual and assertNotEqual is inconsistent in naming with the
> assertOpFoo class of functions
Not quite. assertEqual() doesn't explicitly test opEqual(). It uses ==. So, it
works with primitives as well as structs that didn't declare an opEquals().
assertOpCmp() on the other hand, explicitly calls opCmp() - so, for instance,
assertOpCmp!"=="() specifically tests that opCmp() returned zero rather than
using ==. However, assertOpOpAssign doesn't actually call opOpAssign(), so there
arguably is an inconsistency there. I'll have to think about how it would be
best to adjust those names. I think that assertEqual() should definitely stay
assertEqual() - it doesn't explicitly call opEquals() and other unit testing
frameworks frequent have a function named assertEquals(), so it will be more
familiar to many. I also think that assertOpCmp!() should stay as it is, since
it is explicitly calling opCmp(). The really question is what to rename
assertOpOpAssign!() to, since like with assertEqual(), it would be too
restrictive to directly call opOpAssign(), and I can't rename it
assertOpAssign() because opAssign() is something else entirely. So, if a
different name would be better, I'm going to have to find one, since I don't know
what else to name it.
> I believe these assertions should be added:
>
> - assertExcThrown and assertExcNotThrown with a default T (should be
> Exception, not Throwable)
That's not a bad idea, though personally, I tend to think that if someone used
an Exception rather than a derived type that they aren't be specific enough (I'm
sure that many would argue with me on that one though). It might work to just
give it a default parameter (and I do agree that the default should be Exception
rather than Throwable).
> - something equivalent to std.algorithm.equal, the latter is very useful in
> unittests
I'm not sure that I'd noticed std.algorithm.equal() before. That's a good idea.
assertEqual() could simply be templatized in the same manner as
std.algorithm.equal().
> - assertOpBinary, assertTrue and perhaps assertPred (where the predicate is
> an template alias parameter)
I decided that assertTrue() was a waste of time, because that's what a bare
assert does. The same goes for assertFalse(), because all you have to do is add
! in front of the expression. All of the functions that I have are there to
either improve the output (such as printing out the actual values of the two
values being compared in assertEqual()), or they get rid of boilerplate code
(such as the try-catch block and other details in assertExcThrown!()).
As for assertOpBinary, are you suggesting a function which does the given binary
operation and then compares the result with the given expected result? That
would be a good addition.
As for assertPred. I don't know what that would do. Would that take a predicate
and its parameters and then assert that the result was true? If that's what
you're looking for, then assertPredTrue and assertPredFalse would be better. I
think that you need to clarify quite what you meant though.
I pretty much created the unit test functions which I needed for std.datetime.
So, I'm sure that there are other good ones which could be added. And I think
that we should do so. My main concern though has been that because some version
of these is going to have to go into Phobos when std.datetime does (be it as
private in std.datetime or as its own module), I wanted to try and get the unit
test functions themselves vetted and get them put in their own module. That way
other people can use them, and more can be added later. So, I haven't been as
concerned with finding every possibly useful unit testing function - particularly
when for some of these, you really have to use them to see how useful they
really are. But I'm definitely open to suggestions as to good unit testing
functions to add.
- Jonathan M Davis
More information about the Digitalmars-d
mailing list