[email protected] wrote:
> Em 14/10/2009 17:11, Alexandre Bergel <[email protected]> escreveu:
>
>>> In Squeak 3.10 TestCase >> assert: aBooleanOrBlock
>>> Squeak 3.8, Dolphin and VAST (I don't know others) have: TestCase
>>>>> assert: aBoolean
>>> So...is there a reason of doing that? Is this expected?
>> I do not see any particular reason. But having Object>>assert:
>> aBlock is important, since one can simply redefine assert: in a
>> class to supress all assertions.
>
> Which begs the question: then why the same method is re-implemented in
> TestCase anyway?
...just thinking 'aloud'...
TestCase>>assert:, by convention, accepts a Boolean, and could be
extended to also accept a block (and apparently has been so extended in
Squeak).
Object>>assert: *should* accept a block, and it isn't really useful for
it to accept a Boolean.
As Alexandre says, you can suppress assertions by redefining #assert:.
One could also make Object>>assert: depend on some variable somewhere to
determine whether to actually run the assertion blocks. Then you can
turn assertions on and off system-wide, and not be running that
assertion code in the blocks all the time. If you accepted a boolean,
you'd be running the assertion expression whether assertions were turned
on or not, which is undesirable.
It's not too nice if Object>>assert: and TestCase>>assert: take
different kinds of arguments
TestCase>>assert: takes a Boolean. I suspect that's too widely used to
change.
I don't know how widely used Object>>assert: is. Perhaps we could have a
different selector for that which takes a block. Maybe a selector that
implies more strongly that its argument should be a block. Our test
framework (which I believe predates SUnit) uses #run:forResult:, with a
block for the first argument and the expected result of evaluating the
block as the second argument. I like this for a couple of reasons --
run: strongly implies that it should take a block argument, and giving
the expected result separately allows failure messages of the form
"Expected <a>; got <b>" which is handy anytime but *really* useful when
failures are not easily reproducible.
Regards,
-Martin
P.S. -- the following is marginally related:
In performance-critical code that is executed *very* frequently, even
making a message send and checking whether assertions are turned on or
not can have too much impact. In those situations, I banish all
assertions to a subclass, which has methods of this general form:
someMethod
| result |
self assert: [assertions appropriate on entry to this method].
result := super someMethod.
self assert: [assertions appropriate on exit from this method].
^result.
Then to turn assertions on or off, I have code that can change the class
of the instances, and switch whether new instances are of the
no-assertions class or the with-assertions subclass.
This allows the application to run at full speed when assertions are
turned off, a real advantage in some cases. This also separates the
normal code from the assertion code, which has both advantages and
disadvantages.
_______________________________________________
Pharo-project mailing list
[email protected]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project