SUnit vs. examples and all that Jazz

Klaus D. Witzel klaus.witzel at cobss.com
Tue Aug 15 08:37:30 UTC 2006


On Mon, 14 Aug 2006 17:47:52 +0200, Markus Gaelli wrote:
> Hi Klaus,
> On Aug 14, 2006, at 1:54 PM, Klaus D. Witzel wrote:
...
> Yes. It is about understanding.
> And I claim, that for understanding an entity you need to be able to  
> read it in its context.

This is not reality (we talk about software and its code, don't we?).  
Neither can you force the software developer to read something nor can you  
force any person to understand something. s/you/I/ and set I := Markus,  
I'd agree.

> SUnit just does not give me context of the tested methods and classes.  
> So I need to read it. With SUnit I need to know the "how" _before_ I  
> could understand the _what_. This is not so good OO i.m.h.o.

Yes, something better is needed. How about little stories on the  
whatabouts, perhaps animated. Good example:
- http://connect.larc.nasa.gov/squeak.html

> I claim that the value of examples are underestimated in OO programming.
> Think of a language dictionary like Websters, where you can understand  
> each word, by reading it in an exemplified use. We all learn by example.

You all minus: #Klaus (perhaps). I only learn when I'm able to do it by  
myself or, when I have to explain it to another person (one subsumes the  
other). Besides of that, I can only store information.

>>> Also - we would not find it easily as an example for instance specific  
>>> behavior.
>>
>> I didn't claim that. But, because of what?
>
> Damien asked about a paper about instance specific _behavior_.
> Marcus understood that...

I'm sorry this was not the question. See how hard communication is? I  
asked for the *cause* (like in: because) for your "would not find it  
easily as an example for instance specific behavior". My quesion was not  
about the people you mentioned.

>>> I'd categorize this test as a "method test" focusing on
>>> 	Behavior >> compile: aString
>>
>
>> I'd have to agree if it wouldn't use #subclass: and  
>> #primitiveChangeClassTo:; if you remove these two we'd be in sync with  
>> "focus is on compile: aString testing".
>
> Aehm, here I was fuzzy and should have said that it is actually  
> exemplifying two things, at least for me:
>
> - How to create a behavior
> - How to plug it in
> Interesting that you would also add the subclassing aspect, this would  
> be a technical detail for me (boldly spoken, of course... too much  
> traits stuff going around in our group I guess... ;-) )

Unless you're a friend of "nil subclass: #MyOwnRoot", in St you're always  
subclassing, aren't you? So this cannot be not a technical detail. It's  
like breathing.

>>> 	|aBehavior|
>>> 	aBehavior := self new.
>>> 	aBehavior compile: 'thisIsATest  ^ 2'.
>>> 	^aBehavior
>>
>> Hhm[0.5*OT]: I'm not a friend of sequences of St code which begin with  
>> " := self new; more: "; as soon as "self new" is over you're most  
>> likely on the wrong side (reuseability, extensibility, overridability).
>
> Don't think so for above example. Treat examples as factories - actually  
> you can find a lot of examples of examples ;-) following this factory  
> aspect in Squeak. They are all commands - thus directly executable,  
> which is nice. Why adding another level of indirection here?

I didn't invent the flow of control between "self new" and the immediately  
following instruction, it's intrinsic in St. And I have already added your  
understanding of the issue to my list of "natural" confusions in St ;-)

> Why adding a parallel test class hierarchy?

Because every application always runs without any test class/method being  
present in the .image?

> But as seen below, when I have to add _lots_ of methods after the new to  
> get this instance into a meaningful state, I certainly agree with you!

O.K. dropped you off of the list of software developers who *are*  
"naturally" confused by such constructs ;-)

> But this also fits nicely with the metaphor of examples.

Perhaps I'm too rigid with "... self new ... more: ..". Will think it over.

> Having the mantra of "an example for each concept"  in mind also helps  
> us in coming up with better designs -  we are already starting to  
> discuss if subclassing is a concept necessary for plugging in behavior  
> or if is is mere implementation issue - this discussion is good (though  
> I don't have the time to pursue it...)

This would be interesting to find out. There are perhaps pattern when  
subclassing is necessary and when that's not the case? Keep me up to date,  
if possible, please.

...
>>> ===============
>>> I think this way
>>> - is more object oriented and you could browse the class side of  
>>> Behavior to see how its instances can be applied
>>
>> Hhm[0.5*OT], depends. How many "browse this and that" will we tolerate  
>> until we'd agree on "this one is an easy to understand test or method  
>> or whatsoever". Seriously, what number do you suggest?
>
> I'd say try to exemplify the main concepts your architecture is relying  
> on - think API's. This should lead to a very high  test coverage and  
> better understanding.

Have criteria for "better understanding" at hand? This is too subjective,  
IMO. "interviewer: did you understand this concept? candidate: yes!".

Whether or not something is understood can only be found out if candidate  
is using "it" after getting to known "it". This is where "to understand  
something" begins, here where I am.

> To emphasize this claim even more, I'd say that in the end your  
> acceptance tests / (checked examples of API's) reflecting the typical  
> outside usage your system are enough.

Sure.

> Of course we are all programmers, so we are using this low-level Squeak  
> stuff, and for doing so we need to understand it. So our acceptance  
> tests / examples should exists also for low level stuff.

I have never made any distinction between low and other level in software  
systems, only between provider and user of an interface. Is that what you  
mean?

>>
>>> - you could reuse this instance specific behavior in more tests
>>
>> Reuse, yes! (I understand you meant potentially reused). But we should  
>> not discuss that "this and that has potential for being reused" unless  
>> there are already ~= 1 users (proof of concept exists, at least).
>
> One advantage of viewing tests as checked examples / factories is above  
> explained documentation value:
> People like Damien might look into Behavior (examples) category to find  
> out what is already there...

If you always keep test cases and other "test supporting" methods in your  
image: yes. But that is an illusion.

> An other advantage (reuse of this technique ;-) is the _possible_ reuse  
> of these instances in different contexts.

Okay, tell me one example where a test method has been reused (not  
[re]factored!), please.

> Other arguments include cohesion of test and code, principle of last  
> surprise (examples and tests are one of a kind (commands / factories),  
> tests just come with some assertions), no parallel test hierarchy, ah,  
> and no need for static typing your instance variables - the set of  
> examples should include all possible concrete types these variables can  
> take. (Same argument for method parameters btw.)

Sure.

>> Hhm, matter of taste here? I prefer verbose tests, unless there is an  
>> already implemented method which I can reuse (which is not the case  
>> here, I mean #superclass: - #setFormat: - #primitiveChangeClassTo:).
>
> I'd like to have a browser, where you could fold in and out code, so if  
> you liked you could see above "exampleCompileThisIsATest" inlined (maybe  
> even edit it there).

+ (1 big) perhaps Stefan's Christo can be a start here?

>> "You shall not write *new* methods just in support of tests, they are  
>> superflous and do by no means reflect the testee's situation." Now how  
>> about this?
>>
>>  "Object >>
>
> no helper methods which are only used by other tests. But if these  
> "helper methods" also exemplify the usage of other real methods - why  
> not?

Because I do not pay my employees (and freelancers) for inventing test  
helper methods. It's Okay for (re)factoring test methods, but that is  
where the story ends here.

By nature of definition, all test methods are unique!

Rule of thumb: the more you have (or like) to invest into test methods,  
the less the subject (the testee) is understood.

> Certainly I agree that methods doing some real work always should be  
> factored into the real code.

Ahh, my rule of thumb at work :)

> As been suggested in our taxonomy paper Stefan Reichert uses the fifth  
> pane in Christo to display tests right to the methods they are calling.
> He has not (yet? ;-) introduced the idea of an exemplified method,  
> rather all methods called in the test now can display this test as an  
> example.
>
> Besides Stefan went a bit further in an other direction concerning this  
> linkage of methods and tests, and also introduced a fifth pane the other  
> way round: A test also displays all methods called by it to its right.

Yes, I've seen that and Stefan did a tremendous job-very good work.

/Klaus

> Cheers,
>
> Markus
>
>
>





More information about the Squeak-dev mailing list