Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Unit testing - suitable for all development?

Reply
Thread Tools

Unit testing - suitable for all development?

 
 
Kylotan
Guest
Posts: n/a
 
      03-07-2004
Today I tried to implement some sort of unit testing into my program
for the first time, and must admit to being a little disillusioned
with the process. Mainly, my issue is that in my program, the classes
are so tightly coupled that testing in isolation is next to
impossible.

The main problem stems from the fact that I try to ensure that all my
objects are created in a working state. This often means passing
various other objects to the __init__ function. In turn, these other
objects rely on others, and on general initialisation procedures. The
end result is that there are very few objects I can truly test in
isolation; I have to initialise at least 80% of the system before I
can even create most of my objects. This ends up meaning that unit
testing isn't really testing a single unit at all, and in fact isn't
much more precise than liberally using asserts in the normal code.

One way out of this would be to reduce coupling. This would allow me
to test objects in relative isolation, but it would increase the
amount of explicit coupling code that I'd have to execute normally.
This extra code then becomes a potential source of new bugs.

Has anybody else come to similar conclusions?

--
Ben Sizer
 
Reply With Quote
 
 
 
 
John Roth
Guest
Posts: n/a
 
      03-07-2004
"Kylotan" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) m...
> Today I tried to implement some sort of unit testing into my program
> for the first time, and must admit to being a little disillusioned
> with the process. Mainly, my issue is that in my program, the classes
> are so tightly coupled that testing in isolation is next to
> impossible.
>
> The main problem stems from the fact that I try to ensure that all my
> objects are created in a working state. This often means passing
> various other objects to the __init__ function. In turn, these other
> objects rely on others, and on general initialisation procedures. The
> end result is that there are very few objects I can truly test in
> isolation; I have to initialise at least 80% of the system before I
> can even create most of my objects. This ends up meaning that unit
> testing isn't really testing a single unit at all, and in fact isn't
> much more precise than liberally using asserts in the normal code.
>
> One way out of this would be to reduce coupling. This would allow me
> to test objects in relative isolation, but it would increase the
> amount of explicit coupling code that I'd have to execute normally.
> This extra code then becomes a potential source of new bugs.
>
> Has anybody else come to similar conclusions?


Coupling is the enemy.

The XP people have a lot of experiance with reducing
coupling. Writing tests first, and insisting that literally
hundreds of unit tests run in a few seconds teaches you
how to write code with a minimum of coupling. Some of
those lessons aren't particularly easy.

I'm very much a fan of creating objects in a state so that
the object invariants pass. I've got two suggestions.

The first is to see if you can redesign using a layered
architecture. That may force you to reduce the number
of objects that any given object depends on.

The second is to investigate mock objects, or other
methods of stubbing out dependencies. While you do
need to run the entire system as a unit, there is no
reason you need to run the real production objects
for all tests.

John Roth
>
> --
> Ben Sizer



 
Reply With Quote
 
 
 
 
Roy Smith
Guest
Posts: n/a
 
      03-07-2004
http://www.velocityreviews.com/forums/(E-Mail Removed) (Kylotan) wrote:
> Today I tried to implement some sort of unit testing into my program
> for the first time, and must admit to being a little disillusioned
> with the process. Mainly, my issue is that in my program, the classes
> are so tightly coupled that testing in isolation is next to
> impossible.


Yup, this is often a problem when you first start unit testing. Tightly
coupled classes are difficult to test.

Tightly coupled classes cause lots of problems too. They make it hard
to understand how your system works, and they make it hard to change out
components later. One of the things that unit testing does is it forces
you to write classes so they are easily testable, which usually means
not a lot of inter-class dependencies.

> The main problem stems from the fact that I try to ensure that all my
> objects are created in a working state. This often means passing
> various other objects to the __init__ function.


That's fine. Let's imagine you've got:

class Foo:
def __init__ (self, language, timeZone, hairColor):
self.language = language
self.timeZone = timeZone
self.hairColor = hairColor

def getBreakfastFood (self):
do a lot of stuff involving language, etc
return (food)

class Bar:
def __init__ (self, foo):
self.foo = foo

On the surface, it looks like you can't test Bar without having a
working Foo. But maybe you can provide a stub implementation of Foo
which does just enough to allow Bar to be tested:

class FooStub:
def getBreakfastFood (self):
return "spam"

then you can do in your TestCase class, something like:

def setUp (self):
foo = FooStub ()
self.bar = Bar (foo)

and you're all set. This assumes that there's something about Bar's
behavior which depends on foo having a getBreakfastFood () method which
actually works. If the classes were less coupled, Bar might do nothing
with the foo it was passed other than treat it as opaque data to be
retrieve by a getFoo() method. In which case, your stub class could be
even simplier:

class FooStub:
pass

and you might even be able to get away with no FooStub class at all, but
simply instantiating your Bar test object with a constant:

def setUp (self):
self.bar = Bar ("foo")

This is where the dynamic nature of Python really shines. Something
like C++ or Java would make you jump through a lot more hoops to make
sure you instantiated your Bar with a valid Foo. But the basic
principle is the same in any OOPL; the more tighly coupled your classes
are, the more difficult it is to test, maintain, and understand the
system.

> One way out of this would be to reduce coupling. This would allow me
> to test objects in relative isolation, but it would increase the
> amount of explicit coupling code that I'd have to execute normally.
> This extra code then becomes a potential source of new bugs.


One way or another, your classes need to interact, and the code that
implements those interactions needs to exist (and thus needs to be
tested). The question is, where do you put that code? Do you bury it
inside the classes, making it difficult to test both the underlying
classes and their interactions, or do you factor it out to someplace
where you can test each piece in isolation?
 
Reply With Quote
 
Kylotan
Guest
Posts: n/a
 
      03-07-2004
"John Roth" <(E-Mail Removed)> wrote in message news:<(E-Mail Removed)>...

> Coupling is the enemy.
>
> The XP people have a lot of experiance with reducing
> coupling. Writing tests first, and insisting that literally
> hundreds of unit tests run in a few seconds teaches you
> how to write code with a minimum of coupling. Some of
> those lessons aren't particularly easy.


Yeah, that's what I'm guessing. I'm at the stage where I have to
wonder whether forcing myself to make the paradigm shift will be worth
the effort or not.

> The first is to see if you can redesign using a layered
> architecture. That may force you to reduce the number
> of objects that any given object depends on.


What do you mean by layered in this context? Are you talking things
like the Bridge design pattern?

> The second is to investigate mock objects, or other
> methods of stubbing out dependencies. While you do
> need to run the entire system as a unit, there is no
> reason you need to run the real production objects
> for all tests.


That seems like a nice idea, but I've been developing this system as
an evolving prototype. I add new objects and classes as I discover I
need them. Therefore there's almost no functionality there at all that
isn't needed for the system as it stands.

Here's an example of my current system: the Creature class requires a
Race class and a World class to be instantiated, as the Creature's
__init__ function relies on calling methods of these objects (not just
on their presence). Sure, technically I could create dummy objects to
pass in that have do-nothing functions, but then I break most of
Creature's accessors, which are implemented in terms of delegating to
the other objects. In turn this would make the tests meaningless.

I guess what I'm trying to say is that I create systems that arise
from the grouping of classes, and that taking the class out of context
makes it useless. I don't have many things that are low-level enough
to make sense when tested in isolation. (This contrasts heavily to my
development in C++, for example.) And the classes have very little
internal behaviour; it's all done in terms of other classes.

None of this makes testing any harder or less useful in catching bugs;
it just means that it ends up being an almost straight duplication of
my normal code, with the input handling stripped out! It hardly seems
worth the effort.

--
Ben Sizer
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Webinar - Testing the Untestable - Unit Testing Dependencies andLegacy Code (in C++) Avi C Programming 0 06-11-2012 01:55 PM
[ANN] Webinar - Testing the Untestable - Unit Testing Dependenciesand Legacy Code in C++ Avi C++ 0 06-06-2012 11:25 AM
unit-profiling, similar to unit-testing Ulrich Eckhardt Python 6 11-18-2011 02:00 AM
Unit testing errors (testing the platform module) John Maclean Python 1 04-13-2010 02:11 PM
Test::Unit - Ruby Unit Testing Framework Questions Bill Mosteller Ruby 0 10-22-2009 02:02 PM



Advertisments