NYCPHP Meetup

NYPHP.org

[nycphp-talk] Why do unit tests not inherit?

Robert Stoll rstoll at tutteli.ch
Fri Nov 15 10:58:45 EST 2013


> -----Original Message-----
> From: talk-bounces at lists.nyphp.org [mailto:talk-bounces at lists.nyphp.org]
> On Behalf Of Michael Hernandez
> Sent: Friday, November 15, 2013 4:43 PM
> To: NYPHP Talk
> Subject: Re: [nycphp-talk] Why do unit tests not inherit?
> 
> On Nov 15, 2013, at 10:26 AM, "Gary A. Mort" <garyamort at gmail.com>
> wrote:
> >
> > Is there a reason that most unit tests published for PHP Open Source
> projects do not use OOP programming?
> >
> > --
> > Class Pets
> > Class Dogs extends Pets
> > Class Cats extends Pets
> >
> >
> > Unit tests written for those classes generally are defined like Class
> > TestPets extends TestCase Class TestDogs extends TestCase Class
> > TestCats extends TestCase
> >
> >
> > It seems to me that it should be
> > Class TestPets extends TestCase
> > Class TestDogs extends TestPets
> > Class TestCats extends TestPets
> >
> > That way if the Pets base class is given a new method based on a method
in
> Dogs but with subtle differences, by inheriting the TestPets unit tests
you will
> immediately find out that the Dogs class is failing the Pets unit tests
and
> either needs to be changed to match or if it is supposed to be different,
the
> test from TestPets has to be disabled in TestDogs.
> >
> > I'm trying to wrap my brain around this and wondered if there is some
valid
> reason for not using inheritance for tests in this way - or if it is just
that for
> whatever reason when programmers first started writing unit tests they got
> stuck in a functional rather than object oriented mindset?
> >
> > -Gary
> > ________________________________
> 
> You could have a hierarchy like the one you describe but I wouldn't work
too
> hard to make that fit. Tests should be as simple as possible and thus
> shouldn't require anything special to get their work done (yes,
inheritance is
> pretty special). Essentially you want to avoid complex inheritance, logic,
> looping, etc., in order to avoid your tests needing tests or documentation
of
> their own.
> 
> That being said, if you find that all "pet tests" require some common set
up,
> you might refactor in the way you mentioned above. Personally, I would
> avoid that until absolutely necessary. I would even go so far as to say
that
> sticking to DRY isn't as important as having clear tests that not only
give you
> confidence that your code works but also serve as living documentation.
> Having important bits squirreled away into base classes can make things
> harder to read sometimes. Whether or not having code in another class
> separate from your test increases the clarity of your code is entirely up
to the
> reader, of course ;)
> 
> --Mike H

I totally agree with Mike. I have already started writing so I continue
(even though it is some repetition of Mike's answer)
IMO tests have to be simple, so simple that you do not require to apply
software engineering and think about a fancy design etc. 
That's at least the case if you write real unit-test which involve just one
unit (class) and not more (all dependencies are stubbed or mocked).

I even think it is ok to have some degree of code duplication in test
classes just to make the test case very obvious. 
Each test case should ideally just cover one aspect (method) and if you
start having a lot of test cases for just one method, then you should
probably refactor your method.
Also if your test method starts to get bigger and bigger it is probably time
to refactor your method under test.

I usually create one method in the test class which provides me the unit
(class) under test and I write code against interfaces.
For your scenario I would create one test class which covers Pet and another
for Dog and yet another for Cat. The test classes for Dog and Cat would just
contain test methods for the additional functionally of Dog, Cat
respectively.
However, if you start overriding methods in Dog or Cat, then I would create
two sub-classes of the Pet test class and merely override the create method
(exchange Pet with Dog, Cat respectively). This way you can make sure your
code fits to the Liskov Substitution Principle but without making your test
code more complex.

I also ran into code where it was no longer possible to follow this
approach, but this was mostly an indicator that the code needs refactoring.

Cheers,
Robert



More information about the talk mailing list