From 820f2f6bba92832ca03abc1a7ce94e53846c001f Mon Sep 17 00:00:00 2001 From: "Jens W. Klein" Date: Thu, 16 Jul 2026 12:03:12 +0200 Subject: [PATCH] Enrich public API docstrings for autodoc and IDE help The docstrings of the most-used testing helpers and layer classes were thin one-liners: applyProfile documented none of its six parameters, cleanUpMultiPlugins had no docstring at all, and IntegrationTesting / FunctionalTesting said only 'Plone version of the ... testing layer'. Enrich login, logout, setRoles, applyProfile, cleanUpMultiPlugins, IntegrationTesting and FunctionalTesting with parameter descriptions (reST field lists) and behaviour notes. No behaviour change, docstrings only. This is groundwork for an autodoc-generated API reference in the Plone documentation, and improves IDE help in the meantime. --- news/+enrich-api-docstrings.documentation | 6 +++ src/plone/app/testing/cleanup.py | 7 ++++ src/plone/app/testing/helpers.py | 47 ++++++++++++++++++++--- src/plone/app/testing/layers.py | 23 ++++++++++- 4 files changed, 76 insertions(+), 7 deletions(-) create mode 100644 news/+enrich-api-docstrings.documentation diff --git a/news/+enrich-api-docstrings.documentation b/news/+enrich-api-docstrings.documentation new file mode 100644 index 0000000..3e4c277 --- /dev/null +++ b/news/+enrich-api-docstrings.documentation @@ -0,0 +1,6 @@ +Enrich the docstrings of the public testing helpers and layer classes +(``login``, ``logout``, ``setRoles``, ``applyProfile``, +``cleanUpMultiPlugins``, ``IntegrationTesting``, ``FunctionalTesting``) +with parameter descriptions and behaviour notes. +This makes them usable as an autodoc API reference and improves IDE help. +[jensens] diff --git a/src/plone/app/testing/cleanup.py b/src/plone/app/testing/cleanup.py index e0d9957..f299345 100644 --- a/src/plone/app/testing/cleanup.py +++ b/src/plone/app/testing/cleanup.py @@ -16,6 +16,13 @@ def cleanUpMultiPlugins(): + """Remove PAS MultiPlugin registrations left in the global registry. + + Registered as a ``zope.testing`` cleanup handler, so it runs + automatically between test layers and keeps global PluggableAuthService + state from leaking from one layer into the next. Plugins that + GenericSetup's own cleanup handler already manages are left untouched. + """ try: from Products.PluggableAuthService.PluggableAuthService import MultiPlugins diff --git a/src/plone/app/testing/helpers.py b/src/plone/app/testing/helpers.py index 887cde5..e9d6f9b 100644 --- a/src/plone/app/testing/helpers.py +++ b/src/plone/app/testing/helpers.py @@ -22,19 +22,39 @@ def login(portal, userName): - """Log in as the given user in the given Plone site""" + """Log in as the named user in the given Plone site. + + Subsequent operations run as this user until :func:`logout` is called + or the test tears down. + + :param portal: the Plone site to log in to. + :param userName: the login name of the user to become, for example + :data:`TEST_USER_NAME`. This is the login name, not the user id. + """ zope.login(portal["acl_users"], userName) def logout(): - """Log out, i.e. become anonymous""" + """Log out, so that subsequent operations run as the anonymous user. + + The inverse of :func:`login`. + """ zope.logout() def setRoles(portal, userId, roles): - """Set the given user's roles to a tuple of roles.""" + """Set a user's global roles to exactly the given roles. + + Replaces the user's current roles rather than adding to them. + + :param portal: the Plone site. + :param userId: the id of the user whose roles to set, for example + :data:`TEST_USER_ID`. This is the user id, not the login name. + :param roles: the roles the user should have, as a sequence of role + names, for example ``["Manager"]``. + """ userFolder = portal["acl_users"] zope.setRoles(userFolder, userId, roles) @@ -105,8 +125,25 @@ def applyProfile( archive=None, blacklisted_steps=None, ): - """Install an extension profile into the portal. The profile name - should be a package name and a profile name, e.g. 'my.product:default'. + """Install a GenericSetup extension profile into the portal. + + Runs every import step of the profile as the site owner, then rebuilds + the current skin. Use this to install an add-on into the test site, + typically from a layer's ``setUpPloneSite`` or directly in a test. + + :param portal: the Plone site to install the profile into. + :param profileName: the profile id in ``package:profile`` form, for + example ``"my.product:default"``. Give it without the ``profile-`` + prefix; that is added internally. + :param purge_old: passed through to GenericSetup. When ``None`` (the + default) GenericSetup decides; ``True`` purges existing settings + before importing, ``False`` keeps them. + :param ignore_dependencies: when ``True``, run only the profile's own + import steps and skip the profiles it depends on. + :param archive: an optional GenericSetup archive (tarball) to import + from instead of the profile directory. + :param blacklisted_steps: an optional sequence of import step ids to + skip. """ from AccessControl import getSecurityManager diff --git a/src/plone/app/testing/layers.py b/src/plone/app/testing/layers.py index d61ff0f..a845561 100644 --- a/src/plone/app/testing/layers.py +++ b/src/plone/app/testing/layers.py @@ -398,11 +398,30 @@ def testTearDown(self): class IntegrationTesting(PloneTestLifecycle, zope.IntegrationTesting): - """Plone version of the integration testing layer""" + """Testing layer for integration tests. + + Wraps a Plone site fixture with per-test isolation: each test runs + inside a transaction that is rolled back on tear-down, so tests do not + see each other's changes. Derive one from your fixture with + ``IntegrationTesting(bases=(MY_FIXTURE,), name=...)``. + + Use this for in-process tests. When a test makes a real HTTP request, + use :class:`FunctionalTesting` instead. + """ class FunctionalTesting(PloneTestLifecycle, zope.FunctionalTesting): - """Plone version of the functional testing layer""" + """Testing layer for functional tests. + + Like :class:`IntegrationTesting`, but each test runs against a stacked + ``DemoStorage`` and may commit real transactions, which a separate + process such as a browser or HTTP client can then see. The storage is + discarded on tear-down. + + Use this when a request has to travel over the network, for example a + REST API or browser test. Add ``WSGI_SERVER_FIXTURE`` to the bases so a + server is running. For in-process tests, use :class:`IntegrationTesting`. + """ class ZServerFunctionalTesting(PloneZServerTestLifecycle, zserver.FunctionalTesting):