|
|
|
Death to ZopeTestCase!There's a beast in Zope 2 that needs to die. Its name is ZopeTestCase. Integration tests are goodI won't condemn ZopeTestCase entirely. It actually serves a good purpose: to test how a particular Zope 2 object (a Zope 2 meta type, a CMF portal tool, a content object, etc.) behaves in a Zope 2-like environment, which essentially means inside a folder hierarchy with acquisition and all the bells and whistles. Because of the way many Zope 2 solutions were written, this is pretty much the only way you would test them anyways, because they rely on having an acquisition context, the REQUEST available all the time, etc. Still, calling a ZopeTestCase test a unit test is pure blasphemy. It's an integration test. Unit tests are important, tooThe problem with ZopeTestCase is that it's so convenient and it lures test authors into a type of test that they probably didn't want to write and definitely shouldn't. Sure, integration testing is important and, as said above, ZopeTestCase actually serves that purpose. Unit tests are also important, though. And as Zope 2 software is being componentized, they're actually much easier to write. The CMF, for example, doesn't use ZopeTestCase (except for one test which probably shouldn't use it, either). ZopeTestCase's problemThe problem with ZopeTestCase is really a technical one. It is the way it provides integration testing facilities:
The problem: there's no tear down and therefore no isolation. If I have unit tests and ZopeTestCase tests running together, the unit tests will be executed in the context of ZopeLite and all the initialized products that other tests wanted to have installed. For this reason, for example, you're definitely asking for trouble when doing installProducts('Five') because that loads all of Five's ZCML, therefore registers things that your unit tests might not expect to be there. The new testrunner's solutionSince Zope 3.2/2.9, we have a new testrunner in zope.testing. The test.py script is a small facade for it. The new testrunner supports a concept called layers. Layers are levels of test setup and all tests of the same layer are executed at once. From zope.testing's testrunner.txt: Most tests are unit tests. They don't depend on other facilities, or set up whatever dependencies they have. For larger applications, it's useful to specify common facilities that a large number of tests share. Making each test set up and and tear down these facilities is both ineffecient and inconvenient. For this reason, we've introduced the concept of layers, based on the idea of layered application architectures. Software build for a layer should be able to depend on the facilities of lower layers already being set up. (...) How layers workLayers are objects with setUp and tearDown methods. When using classes as layers, we must use class methods:
class MyLayer(object):
@classmethod
def setUp(self):
# do something here
@classmethod
def tearDown(self):
# undo it here
You can nest layers using class inheritance:
class MyExtendedLayer(MyLayer):
@classmethod
def setUp(self):
# do additional stuff here
# don't call super
@classmethod
def tearDown(self):
# undo it only the additional stuff here
# don't call super
The test runner will first set up MyLayer and run all tests of that layer. Then it will set up MyExtendedLayer and run all tests of that layer. When done, it will tear down MyExtendedLayer, then MyLayer. As you can imagine, this allows very fine grained test setup. For example, there can be a very general layer that bootstraps common things; specific tests can then supply their own test setup based on that layer (by subclassing from the layer). Using layers for integration testsIn Zope 3, unit tests simply have no layer. Integration tests (we call them "functional tests") that rely on a full-blown ZCML setup (starting at ftesting.zcml) can use zope.app.testing.functional.ZCMLLayer, for example. Other tests use their own layer. I think ZopeTestCase, specifically ZopeLite, should be converted into a test layer. The trick is that it will also support tear down. The installProduct functionality should also be moved into layers, ones that obviously extend the ZopeLite layer. Again, tear down will be possible so that tests will be able to say which specific products they need (right now, all tests run with all the products installed that are somewhere specified as dependencies). I think this might be a nice sprint task. Paris, Switzerland, EuroPython... anyone? Comments
Posted by Philipp von Weitershausen @ 03/10/2006 04:37 AM.
-
3 comments
|
Latest blog posts
Latest animations
Latest documents
|
||