Integrating pure Python tests with PloneTestCase
Running tests takes long enough as it is...
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 a file named batching.py on the root level of my Product (along with a little doctest testing some arbitrary edge cases):def batch(items=[], batch=0, batchsize=5):I can use this method in my product with the following import statement:
"""returns a batch from the given items
>>> 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, 11]
"""
if batch >= batchnum(len(items), batchsize):
raise IndexError, \
"No batch number %d" % batch
else:
return items[batch * batchsize:(batch+1) * batchsize]
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:if __name__ == "__main__":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!
import doctest
doctest.testmod()
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 unittestEdit: removed some superflous code in the examples.
from unittest import TestSuite
from zope.testing.doctestunit import DocTestSuite
def test_suite():
return TestSuite((
DocTestSuite('Products.PRODUCTNAME.batching'),
))
if __name__ == '__main__':
unittest.main(defaultTest="test_suite")
