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]>
