Robin Szemeti <[EMAIL PROTECTED]> writes:

> On Tue, 13 Feb 2001, you wrote:
> 
> > > to wit, testing of object based modules. Firstly what do people generally
> > > use for this? Test::Unit ?? or is there something more freindly out
> > > there?
> > 
> > Test::Unit *almost* does the right thing, but looking through the code
> > there are some horrible things being done (by someone who doesn't seem
> > to understand the reflection/introspection and dynamic features of
> > Perl),
> 
> they didn't even understand 'use strict;' so I expect there are other
> gaps too
> 
> since it does *almost* the right thing and I *almost* know what I'm doing
> with it .. I'll hang with it then for now.
>    
> > and the test suite it comes with doesn't seem to have
> > desperately good coverage of the various testing modules. Which is why
> > I'm working on it...
> 
> uh huh .. I noticed various bits of the Tk gui were a little err 'sub
> obtimal' :) ... 
> 
> lerrus know when you get it nailed down then.
> 
> > > secondly abstraction:
> > > 
> > > If I have , say a 'data' object 
> > 
> > Why does the data object have to know how/if it's stored? Have a data
> > librarian object which is responsible for handling moving objects into
> > and out of storage. Then test the librarian to make sure that it can
> > retrieve stuff in the appropriate fashion, and do your data object
> > unit testing (possibly) without even having the librarian loaded up.
> > If you *do* find that you need to have the librarian loaded for some
> > of the data object's methods to work, think hard and see if you can't
> > find some way of removing that dependency. 
> 
> uh huh ... sorta got that ... so basically anything with anything that
> looks like sql or a $dbh handle ends up in the Librarian .. the outer
> class has all the other stuff .... I aint sure about the 'without even
> having the librarian loaded' bit .. surely you test the librarian and
> then test the outer class with the librarian loaded iff the librarian
> passes its tests? .. otherwise you end up having to write a dummy
> librarian class that has every chance of not correctly behaving as the
> real librarian .. or do you just run the librarian tests on the dummy
> class as well?/ ... I though the idea was to build from ground zero, and
> include tested base classes into higher order classes and then test them
> as you go along .. or is that not it? ... 

Okay, we're into 'ideal situations here', but here goes.

Consider a clothes catalogue, with, say, the following classes:

ProductLine (ie Levis 501s)

StockItem, inherits from ProductLine (ie Levis 501s, 32W 34L, stone
washed)

Then, to set up the objects we'd do something like:

  my $levis = 
      ProductLine->new(category_name => 'Levis 501s',
                       description => '...',
                       stock_item_attribs => [...]);

  $levis->new_stock_item(waist => 32, length => 34,
                         finish => 'blue stonewashed',
                         quantity => 100);

The new_stock item method would then create a stock item (possibly
with a weakref back to its parent productline, but that's dependent on
whether we're ever going to need to use that...), and one of the
product lines would have a list of stock items associated with it.

Then, we could write a method to find all the actual items in stock by
doing something like:

   sub ProductLine::items_in_stock {
       my $self = shift;
       grep {$_->quantity > 0} $self->stock_items;
   }

Which wouldn't have to deal with the database at all.

If the librarian does the Right Thing, then we could say to it:

   $librarian->store($levis) 

and it would go away and store not only the $levis ProductLine object,
but also its associated stock items. And, when we come to reload the
$levis productline then it will either reload all its stock items, or
will place 'proxy' objects in their place which will trigger the
reloading of the real object when required. (Doing it this way stops
the reload of a single item doing a 'six degrees of separation' trick
and pulling in the entire object web.)

At a higher level, we could stick all our product lines into some top
level Catalogue object and simply stash that in the database, but it may
be that we should actually conflate the Catalogue with the librarian
to make for more memory efficient searches for products.

The point of taking this approach is that, when we want to test
ProductLine and StockItem there is no need to worry about how they are
stored, we can simply write a bunch of code that sets up a bunch of
productlines and stockitems and test away in that environment. 

When we want to test the Catalogue, then of course we're going to need
a database standing by, but we can use a dummy, empty database, set up
a bunch of objects, store 'em and test that storage and reloading work
like they're supposed to.

Which is, admittedly, not the initial approach I mentioned to you in
private email, but I've thought about it some more since then.

> > The difference between a Unit test and an Acceptance test is that the
> > unit test tries its damndest to test the behaviour of the class and
> > its methods etc independently of everything else in the system.
> > An Acceptance test then tests that the entire system behaves as it
> > should for a given task.
> 
> oh right .. thats a bit clearer ... so what do you do when a class works
> with its dummy stubs but fails when a sub-class is plugged in instead? in
> the latter model that would not get picked up until the acceptance test
> ... and then it might be difficult to see exactly where it went worng... 
> 
> hmm the trick seems to be not so much in the semantics of perl (the whole
> OO thing of method dispatch and inheritance is fairly straightforward
> really now I get to grips with it ) its mainly down to the design and
> subtlties of which bits go in where ... 

You said a mouthful there. I find that OO design seems to swing back
and forth between being completely intuitive and being a hellishly
arcane black art.

-- 
Piers

Reply via email to