On Mon, Mar 29, 2010 at 8:34 PM, Ingy dot Net <[email protected]> wrote:
> I want to learn unittest since it is core. Now I can tell people to run
> 'python setup.py test' or simply 'make test' and it will always do the right
> thing.
> I have a project called TestML that is a programming language agnostic unit
> test language. I'll be talking about it (along with C'Dent) at the upcoming
> meeting.

Just because Unittest is core doesn't mean it's great. You may enjoy
learning it and it may help you understand Python, but the time it
requires has to be weighed against what you can accomplish with a more
capable test engine. There's a reason several projects have switched
to Nose, and it's because Unittest is so limited in test discovery and
so Javaesque in test structure. Nose has plugins! You can spend your
time writing a custom plugin for some esoteric feature, while it zips
along importing submodules for you.

Supposedly the Unittest way to collect tests in submodules is for each
module to provide a function that returns a test suite; i.e., a
collection of all its test cases. Then you aggregate all those into a
compete suite and run it.  That avoids calling unittest.main() in
every submodule. I think you can pass a test suite to the top-level
unittest.main()?

That doesn't help with the importing step though. Parsing module paths
and using __import__() gives me the shivers, especially if I have to
recursively __import__() through packages or modify sys.path in an ad
hoc manner. But it can be difficult to get around it sometimes.
Alternatives include execfile and the various compile functions.
Python 2.7 / 3.2 has a bunch of Unittest enhancements; there might be
something for better discovery.

> Cheers, Ingy
> PS. It turned out the setup.py only ran the first test, if I had multiple
> tests. That is because unittest calls sys.exit!! That seems evil to me.

I think this was mentioned in the Unittest talk at PyCon, as something
fixed in the 2.7 enhancements. I may be wrong about that.

> I
> was overjoyed to find out I could work around this with even more evil. I
> added this to my setup.py:
>         def exit(code):
>             pass
>         sys.exit = exit

At least you recognize that it's evil.

-- 
Mike Orr <[email protected]>

Reply via email to