About use of specific error
Markus Gaelli
gaelli at emergent.de
Fri Mar 3 11:22:58 UTC 2006
Stef,
> can you read what I wrote.... I'm not teaching anything here
> related to first checking if a key exist or not, or
> how to use a dictionary......
>
> I'm teaching them to write tests and to write tests for a class
> that raises exceptions
> you have to catch them and to cover the potential behavior of the
> class! This is not my wish or not to have exceptions, they are
> there and to cover the method behavior (because of different
> programming style) I have to cover them.
Agreed already yesterday. As I said/ wanted to say: Maybe I pushed
the discussing about exception-handling teaching a bit too hard due
to intensive discussions I had with students during _my_ java classes
but:
>
> For example, what happens if we access an element at not existing
> index.
I think overall the discussion here was quite fruitful!
To summarize:
1.) I learned that it makes sense to subclass Error or Exception for
testing reasons.
Otherwise one does not know if an exception was thrown by the method
under test due to a misspelled method name (point of Lukas)
or some other method had a problem on the way (point of Julian).
2.) My point is to use one(!) subclass of Error called
PreconditionError for all unit tests I call "counter examples":
> PreconditionError >> error: aString
>
> so that above became:
>
> IntervalTest >> testRemove
> self should: [(1 to: 3) remove: 2] raise: PreconditionError
I claim that all counter examples check the correct handling of
violating a precondition. Using that abstraction also solves the
problems above.
I invite you all to point out some counter examples for that. ;-)
3.) A very interesting question to ask is if violating a precondition
propagates back -
meaning that if I call a method foo which calls a method bar, which
throws a PreconditionError can be correctly caught with "counter
example" for method foo - even if foo does not(!) contain THAT
precondition.
I think this to be a feature, as otherwise I would have to write the
same preconditions all over again.
Example: I have a method to solve the quadratic equation f(x)=axx+bx+c
Array >> #solveQuadraticEquation
|a b c discriminant solutions |
self precondition: [self size = 3 and: [self allSatisfy: [:each |
each isNumber]]].
"Do I have to state here that the discriminant should be >= 0? I do
not think so."
a:= self first.
b:= self second.
c:= self third.
discriminant:=(b*b)-(4*a*c).
solutions := Set new.
solutions
add:((0-b+discriminant sqrt)/(2*a));
add:((0-b-discriminant sqrt)/(2*a)).
^solutions
If the discriminant<0 the precondition of sqrt should fail. I do not
want to state that here also as I am lazy and as I have not computed
the discriminant in the beginning.
So a "counter example" for solveQuadraticEquation could(!) look like:
ArrayTest >> #testSolveQuadraticEquation
"The following PreconditionError is _not_ thrown by
#solveQuadraticEquation but by sqrt!!!"
self should: [#(1 12 37) solveQuadraticEquation] raise:
PreconditionError
Right now of course sqrt throws a FloatingPointException which is
referenced nowhere (!) in the whole system and which does not contain
any method at all.
This would usually qualify as quite a bogus class.
4.) Actually by using the perspective of PreconditionError I could
spot a possible mistake in the implementation of Interval:
One should be allowed to remove (and add) the first and last element
(s) in an Interval, at least mathematically nothing would speak
against it as long as the invariant of representing a "finite
arithmetic progression" (class comment of Interval) would be intact.
So possibly a better "method test suite" for Interval >>#remove:
would contain a "counter example" and a "method test": (names in
quotes taken from my unit test classification)
IntervalTest >> testRemove
|anInterval|
self should: [(1 to: 3) remove: 2] raise: PreconditionError
anInterval := 1 to: 3.
anInterval remove: 3.
self assert: (anInterval = (1 to: 2))
5.) Andreas, Boris and Pascal point was to use subclasses of
Exception when you are forced to otherwise programmatically deal with
an error string.
I agree with this! Andreas and me were cautious about introducing to
many exception subclasses.
>>>
>>> Not for this one
>>> but
>>> IndexNotFoundError
>>> KeyNotFoundError
>>> SubscriptOutOfBoundsError
We still haven't seen a compelling reason to introduce above
exception-classes. I thought you were proposing them but could not
find any argument for them.
Reading your reply to Andreas it seems that you just wanted to
provoke... ;-)
As I said, I think you provoked a fruitful discussion.
Cheers,
Markus
More information about the Squeak-dev
mailing list
|