[Zope-dev] zope.component test isolation
Martin Aspeli
optilude+lists at gmail.com
Sat Mar 26 07:22:38 EDT 2011
Hi,
On 26 March 2011 08:11, Wolfgang Schnerring <ws at gocept.com> wrote:
> Hello,
>
> * Martin Aspeli <optilude+lists at gmail.com> [2011-03-25 13:58]:
>> plone.testing (which is Plone non-specific and will shortly be BSD
>> licensed) allows for stacking of ZCA registries.
>> [...]
>> Again, plone.testing is the result of hours and hours of finding weird
>> problems, so I'd recommend you don't discard the knowledge there. I
>> think a best case scenario would be for plone.testing.zca to just be a
>> delegate for something more robust in zope.component.testing.
>
> I wasn't aware plone.testing had something for the ZCA, before I read
> that in this thread yesterday. I'm glad to hear that, and I certainly
> don't want to discard anything. But from reading the code and what you
> wrote, I get the impression that plone.testing does not yet solve the
> issue completely, precisely because of the two points I brought up and
> that continue below:
It certainly doesn't solve the "unregister" (non-?)use case. It has
the advantage of being in use in the wild today, though. :-)
>> On 25 March 2011 13:17, Jim Fulton <jim at zope.com> wrote:
>> > On Fri, Mar 25, 2011 at 4:24 AM, Wolfgang Schnerring <ws at gocept.com> wrote:
>> > > we realized that just squeezing in a new registry and bending its
>> > > bases to the previously active one is not enough for full isolation,
>> > > since this does not cover *deleting* registrations
>> >
>> > Is deleting registrations important? This seems like an odd use case.
>> > If it's needed, I would suggest starting with a baseline (e.g. stack)
>> > that doesn't include the component you want to test deleting, then
>> > adding in setup.
>
> I've wanted to specifically nuke registrations sometimes, the pattern
> being, load the package's configure.zcml in the layer, and then delete
> something (to demonstrate some error handling behaviour).
>
> I agree that this use case is rare, but I'm not sure it is rare enough
> that we should ignore it. I need to think about this some more,
> though.
It would be better to explicitly register what you need.
I think you either need to consider a package's ZCML-loaded
configuration as an atomic part of test setup, or you need to break it
down into individual registrations. In the first case, your test
fixture is "package foo's configuration is loaded", which is of course
valid. In the second case, your fixture is "the following components,
some of which happen to be in package foo, are registered".
I don't think a fixture of "package foo's configuration except
component X and Y" is all that useful.
Of course, there may be cases where an unregister is needed, but this
is probably something you should solve locally. For example, you can
explicitly unregister the component at the beginning of your test and
reinstate it at the end of your test, or indeed in layer setup and
tear-down. Automating this with stacking is not a great win.
Please also take my word for it when I say that copying the whole
registry is non-trivial and would rely on brittle ZCA internals. I
tried. :)
>> > > 2. zope.component has two entry points, the global site registry and
>> > > the current registry (getGlobalSiteManager and getSiteManager).
>> > > The current registry can be anything, or more precisely, you can call
>> > > getSiteManager.sethook(callable) and provide a callable that returns
>> > > the current registry.
>> > >
>> > > I think to provide test support for zope.component (i. e. generally,
>> > > at the "library level"), we need to support both entry points.
>> >
>> > Why? Why would someone care about anything other than the current
>> > effective configuration.
>
> Because that's the API that zope.component offers, it conceptually
> deals with *two* registries: the one you get from getSiteManager and
> the one you get from getGlobalSiteManager.
>
> I agree that it is unlikely that client code will *read* registrations
> using getGlobalSiteManager -- since most everyone uses
> zope.component.getUtility etc. (which in turn uses getSiteManager).
> But *writing* is a different matter. Just one example:
> zope.component.provideUtility etc. uses getGlobalSiteManager, while
> the ZCML directives use getSiteManager.
>
> At least as long as zope.component.provide* uses getGlobalSiteManager
> instead of getSiteManager, I maintain that test infrastructure needs to
> 1. wrap the global registry
> 2. wrap whatever getSiteManager currently returns
> (Otherwise we might be able get away with not doing (1), but I think
> we'll always need to do (2).)
>
> plone.testing has it the other way around, doing (1) but not (2), as
> Martin says himself...
We do definitely need to allow the global site manager to be stacked
(which you can achieve with __bases__ as in plone.testing,
unregistration notwithstanding). But once you do that, the rest is
pretty easy. The local site manager will always have the global as one
of its (nested) __bases__.
My preference would be:
- We replace the three separate module-level references to the global
site manager with a single object
- This object is a holder for a registry reference that can be changed
- The registry needs to have a __reduce__ that works with a local
registry is pickled with the global registry as an eventual __bases__
reference
- getGlobalSiteManager() always look up the current value in the
holder, and nothing else looks directly at any module-level variables
With this, we could remove the hacks in plone.testing and move most of
the conveniences down to zope.component.testing if we wanted to.
Martin
More information about the Zope-Dev
mailing list