Unit testing - suitable for all development?

Cameron Laird claird at lairds.com
Mon Mar 8 08:17:20 EST 2004


In article <153fa67.0403071751.157bb860 at posting.google.com>,
Kylotan <kylotan at hotmail.com> wrote:
>Roy Smith <roy at panix.com> wrote in message
>news:<roy-5F604D.12502107032004 at reader2.panix.com>...
>
>> 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.
>
>Yeah, this is true. One of the favourite parts of my system is how I
>have a chain of delegation that passes down a 'graphic' object, and
>nothing except the two classes at the end of the chain need to know
>what type it is.
>
>However, as I think I mentioned in a previous reply on this thread,
>all my methods are there because they're the minimum that I require
>for valid functionality. Stubbing any of them out would make testing
>pointless.
>
>Personally, I don't consider my design to have 'high coupling'.
>However, each coupling is essential. For example, much of my design
>involves delegation; Class A calls an accessor in Class B which gets
>the information from a contained Class C behind the scenes. This
>design is explicitly there so that I have no dependency between A and
>C. However, it also means that I can't test B fairly without C.
>
>Maybe I just have no code that can be tested in isolation. In all
>fairness I don't have much significant code written yet. But as I
>thought you were supposed to code test cases as you go along, I
>thought I'd start now. But in fact it's proven to be pointless.
>
>> 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.
>
>I see one major difference here, though. In C++ I have to write lots
>of low-level classes to encapsulate various elements of functionality.
>These often have few or no dependencies and can be tested in
>isolation. In Python I don't need to write these low level classes, as
>the advanced syntax solves many of these problems for me. Generators
>and list comprehensions replace the need for many function objects.
>Tuples replace ad-hoc structures for returning multiple values.
>Dictionaries replace many of my C++ storage structures. All the
>low-coupling classes I used to write in C++ have been factored out of
>the system by the Python language. All that remains is the core of my
>system; a few specialised classes working in tandem.
>
>As I see it from my -very- limited experience of this one program I'm
>writing, the paradox is that Python makes unit testing so much easier
>and efficient, while making it less and less important to me.
>
>> 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?
>
>There's nowhere it can go that allows for such isolated testing. The
>coupling has to be done in order for the object to make sense. The
>only methods that don't involve other objects are trivial ones that
>are shorter than the associated test case would be.
			.
			.
			.
I'm sympathetic.  Me, too; I don't know how to excerpt your
post, 'cause every paragraph deserves comment.

First, one of the times I most feel like a Python zealot is
in talking about unit testing.  I find it essentially impos-
sible in C++ and Java, because *everything* in those languages
has a huge ratio of set-up to actual test.  It always feels 
like the only test I can make is with the whole program.

Python shifts the balance way to the other side--for the most
part.  I'm still trying to figure out what to advise in your
case.  It sounds as though your implementation has a lot of
clarity, in the sense that your source code simply says what
it means, and so precludes any need for testing.  That's a
good thing.  I have no qualms about asserting that I put my
effort into writing so simply that there can be no mistake.
Maybe your design is that good.

One aspect of testing that I emphasize is exceptions:  how do
my classes handle "bad" data?  I don't understand your situa-
tion well enough to know where this is relevant; if you can
prove that data will always be good, so much the better, but,
in general, I like to know that my classes will behave robustly
when anything goes wrong "upstream".

Like you and some of the other posters, I, too, have the 
instinct that a lack of testability suggests *something* is
amiss with the coupling in your design.  I'd be on the look-
out for an abstraction that further simplifies the relations
between objects.  On the other hand, it sounds as though
you've already searched for such simplifications as much as
you know how.

My conclusion:  I'd probably declare victory by inserting
comments to the effect that, "# I have constructed no unit
test for this class [or aspect X of this class], but instead
rely on inspection to prove that, if inputs A and B have 
properties P and Q, then the result will be S."
-- 

Cameron Laird <claird at phaseit.net>
Business:  http://www.Phaseit.net



More information about the Python-list mailing list