[Product-Developers] Re: Do @onsetup testing functions like setupPloneSite break isolation?

Martin Aspeli optilude at gmx.net
Mon Jun 2 07:31:46 UTC 2008


Hi Ross,

Ross Patterson wrote:
> As I understand it, the documented "best practice" for functional
> testing set up is to do the following at the module level::
> 
>     ptc.setupPloneSite(extension_profiles=['collective.foo:default'])
> 
> For a while now I've had a hard time with the practice of calling the
> ptc.setupPloneSite function in the test module.  When working on the
> tests of several projects at once, which happens often enough, I can't
> run all tests together because one project's use of the PloneSite layer
> is different from another project's use.  Sometimes, for a large
> project, this is even an issue *within* the project's tests.  Quite a
> pain.

Yeah, it's a pain. It's hard in part because ZopeTestCase and 
PloneTestCase in the current released versions do not use layers to set 
up the site (it's done as a module-level call). I believe this is fixed 
in svn, which will make all of this a lot more sane.

The other part of hte pain is that if you do the ptc.setupPloneSite() 
step at a module level (as you have to currently), it's nearly 
impossible to have a set of "fast" unit tests that don't use Plone and a 
set of "slow" integration tests that use the full PTC stack. As soon as 
the test runner goes sniffing for tests, it hits the setupPloneSite() 
call and starts creating a Plone site. :-/

> Before I finally wrote collective.testcaselayer, however, my common
> practice for writing a layer was to do the following::
> 
>     ptc.setupPloneSite()
>     class FooLayer(layer.PloneSite):
>          @classmethod
>          def setUp(cls):
>              app = ZopeTestCase.app()
>              portal = getattr(app, ptc.portal_name)
>              portal.portal_setup.runAllImportStepsFromProfile(
>                  'collective.foo:default')
>              transaction.commit()
>              ZopeTestCase.close(app)
>          @classmethod
>          def tearDown(cls):
>              pass
> 
> Having written collective.testcaselayer, I can now use ptc's addProduct
> and addProfile methods in my layer making this a bit easier and much
> less fragile::
> 
>     ptc.setupPloneSite()
>     class FooLayer(collective.testcaselayer.ptc.BasePTCLayer):
>         def afterSetUp(self):
>             self.addProfile('collective.foo:default')
>     foo_layer = FooLayer([layer.PloneSite])
> 
> So I guess my question is why does the PloneSite layer support
> installing arbitrary add-ons?

Mainly for convenience, I think - helping people hook into the setup 
process at the right time.

> Wouldn't add-on developers be better
> served by a framework that makes the creation of their own layers
> trivial?

Yes.

>  Maybe I'm missing some philosophy or I'm lacking awareness of
> some cases best served by the current approach?  If not, maybe
> this story can be improved using an approach like that of
> collective.testcaselayer?

I think the layering support of PTC needs to be part of the story. I'm 
not sure if that makes collective.testcaselayer redundant. If it 
doesn't, I'd vote to merge the relevant bits of collective.testcaselayer 
into PloneTestCase - it's certainly something we should make easy.

> I guess the same kind of questions can be asked of ZopeTestCase's use of
> module level set up functions as well.  Though I can see this as more
> justifiable since layering global set up is so difficult as to not
> really be worth it. 

I think Stefan made it work. I think it's worth it for the reasons above.

> Better to just clear all global set up and do the
> new global set up afresh when this is needed.  Also, I guess a certain
> amount of this mess is some of the mess we've inherited from the Zope2
> stack.

Nothing's impossible. ;-)

Martin

-- 
Author of `Professional Plone Development`, a book for developers who
want to work with Plone. See http://martinaspeli.net/plone-book





More information about the Product-Developers mailing list