[Zope] FunctionalTestCase commits transactions

Ross Patterson me at rpatterson.net
Mon Nov 3 19:04:54 EST 2008


"Peter Bengtsson" <peter at fry-it.com>
writes:

> I'm trying to get zope.testbrowser to work in Zope 2.10. After a lot
> of guesswork (easy_install zope.testbrowser broke my environment, Zope
> 2.11 isn't setting up session container, used various blogs tips to
> get adapters right) I got it running and I can now do stuff like
> browser.open(self.folder.myapp.absolute_url()) in python unit test.
> However, I have a problem. The app uses ZSQL Methods and when the test
> finishes the transaction is not rolled back and I'm not interested in
> manually resetting the test database.
> Is this so deliberately?
> Do I really have to manually reset the database?
>
> I noticed that FunctionTestCase
> (lib/python/Testing/ZopeTestCase/ZopeTestCase.py:116) inherits from
> functional.Functional which inherits from sandbox.SandBoxed which,
> although I don't understand it, seems to do things differently to the
> non-functional approach which inherits from base.TestCase.
>
> Although I'm not using it, function.Functional adds the nifty function
> publish() which I'm not using but it's not a transaction.commit() in
> it. Why??
> And what does that decorator actually do?

If memory serves, a *functional* test fixture calls the Zope publisher
when a testbrowser request is made.  The publisher opens a new
transaction, as it should.  So if there are uncommitted changes in the
transaction used by the test before submitting the testbrowser request,
then those changes won't be reflected in the new transaction opened when
the publisher handles the request.  I'm guessing that since this is a
fairly common situation it was decided that the test case should commit
before submitting the request to the Zope publisher.

I think it's proper that a *functional* test case opens a new
transaction when responding to requests since that's how the application
behaves.  I also think that it's proper for a widely shared test fixture
such as this to gracefully handle the common case where a test writer
needs changes made in the test to show up when handling the request as
it does now.  I *also* agree that your case is the purer one and that
should be supported.  So I guess I'd advocate for making the commit in
the Functional.publish() method configurable.

At any rate, to solve your immediate problem, I would just write a new
test case class that subclasses whatever test case class you were using,
copy the publish method implementation from Functional and just remove
the commit line.  Then you can use your test case class in your tests
and the commit won't be made.

HTH,
Ross

> class Functional(sandbox.Sandboxed):
>     ...
>     __implements__ = (interfaces.IFunctional,)
>
>     @savestate
>     def publish(self, path, basic=None, env=None, extra=None,
>                 request_method='GET', stdin=None, handle_errors=True):
>         '''Publishes the object at 'path' returning a response object.'''
>        ...
>
>         # Commit the sandbox for good measure
>         transaction.commit()
>         ...



More information about the Zope mailing list