Often, when writing a Plone Product I come across small methods that I need to implement, that actually have no dependency upon Plone itself but are too trivial and/or specific as to warrant putting them into a separate package. If that’s the case for you, too, you will undoubtedly start to get impatient when testing these methods, because with each friggin’ testrun an entire zope instance is created and torn down again. This I have become used to and accept it as part of life as Zope developer, if the code I’m testing actually needs that setup. But it just kept bugging me that I need to wait so long for tests that actually execute in under one second. So I’ve poked around today and came up with the following scenario:
- put your methods into a separate module that has no import dependencies from zope
- add a test runner to that module to execute its tests without starting up zope
- create a test suite for your product that will pick up the tests of your module
1. standalone module
For example, I’ve created a (crude) helper for batching some items in batching.py along with a little doctest testing some arbitrary edge cases:
def batch(items=[], batch=0, batchsize=5): """returns a batch from the given items
A functional test of the private method that calculates batches
>>> items = range(12) >>> batch(items, 3, 5) Traceback (most recent call last): ... IndexError: No batch number 3
>>> batch(items, 0, 5) [0, 1, 2, 3, 4]
>>> batch(items, 1, 5) [5, 6, 7, 8, 9]
>>> batch(items, 2, 5) [10, 11]
>>> batch(items, 2, 4) [8, 9, 10, 12] """ total = len(items) maxbatchnum = batchnum(total, batchsize) if batch >= maxbatchnum: raise IndexError, \ "No batch number %d" % batch else: return items[batch * batchsize:(batch+1) * batchsize
I can use this method in my product with the following import statement:
from Products.PRODUCTNAME.batching import batch
2. add a test runner
Here you just need to follow the straightforward example given in the doctest documentation and add the following snippet to the bottom of batching.py:
def _test(): import doctest doctest.testmod()
if __name__ == "__main__": _test()
Now you can simply execute your module and it will run its tests at blazing speed – buckle up, Dorothy… This definitely makes for much nicer test driven development!
3. Zope integration
Now we just need to make sure, that the tests will also be executed, when we run our Product’s entire suite. This is done by writing a light-weight Testcase based on Zope’s DocTestSuite that ‘picks’ up the standalone tests. I’ve named mine ‘testUtilities.py’ and stuck it right into my Product’s ‘test’ folder:
import unittestfrom unittest import TestSuitefrom zope.testing.doctestunit import DocTestSuite
def test_suite(): return TestSuite(( DocTestSuite('Products.PRODUCTNAME.batching'), ))
if __name__ == '__main__': unittest.main(defaultTest="test_suite")
Tom Lazar: Integrating pure Python tests with PloneTestCase
Originally from Planet Plone by Tom Lazar
http://plonewars.com/2007/08/24/tom-lazar-integrating-pure-python-tests-with-plonetestcase/