Commit 3cee19a4 authored by Hanno Schlichting's avatar Hanno Schlichting

Removed more HelpSys references.

parent 13f7f34f
...@@ -11,6 +11,8 @@ https://zope.readthedocs.io/en/2.13/CHANGES.html ...@@ -11,6 +11,8 @@ https://zope.readthedocs.io/en/2.13/CHANGES.html
Bugs Fixed Bugs Fixed
++++++++++ ++++++++++
- Remove more HelpSys references.
Features Added Features Added
++++++++++++++ ++++++++++++++
......
...@@ -315,7 +315,7 @@ class ZopeIterator(Iterator): ...@@ -315,7 +315,7 @@ class ZopeIterator(Iterator):
return super(ZopeIterator, self).item() return super(ZopeIterator, self).item()
# 'first' and 'last' are Zope 2 enhancements to the TALES iterator # 'first' and 'last' are Zope 2 enhancements to the TALES iterator
# spec. See help/tal-repeat.stx for more info # spec.
def first(self, name=None): def first(self, name=None):
if self.start: if self.start:
return True return True
......
<dtml-var manage_page_header> <dtml-var manage_page_header>
<dtml-var "manage_form_title(this(), _, <dtml-var "manage_form_title(this(), _,
form_title='Add Session Data Manager', form_title='Add Session Data Manager'
help_product='Sessions',
help_topic='session-add.stx'
)"> )">
<FORM ACTION="constructSessionDataManager" METHOD="POST"> <FORM ACTION="constructSessionDataManager" METHOD="POST">
......
<dtml-var manage_page_header> <dtml-var manage_page_header>
<dtml-var "manage_form_title(this(), _, <dtml-var "manage_form_title(this(), _,
form_title='Add Browser Id Manager', form_title='Add Browser Id Manager'
help_product='Sessions',
help_topic='browser-add.stx'
)"> )">
<FORM ACTION="constructBrowserIdManager" METHOD="POST"> <FORM ACTION="constructBrowserIdManager" METHOD="POST">
......
<dtml-var manage_page_header> <dtml-var manage_page_header>
<dtml-var "manage_tabs(this(), _, <dtml-var "manage_tabs(this(), _,
form_title='Manage Session Data Manager', form_title='Manage Session Data Manager'
help_product='Sessions',
help_topic='session-change.stx'
)"> )">
......
<dtml-var manage_page_header> <dtml-var manage_page_header>
<dtml-var "manage_tabs(this(), _, <dtml-var "manage_tabs(this(), _,
form_title='Manage Browser Id Manager', form_title='Manage Browser Id Manager'
help_product='Sessions',
help_topic='browser-change.stx'
)"> )">
<FORM ACTION="manage_changeBrowserIdManager" METHOD="POST"> <FORM ACTION="manage_changeBrowserIdManager" METHOD="POST">
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
o See Also o See Also
- "Transient Object API":../../Transience/Help/TransienceInterfaces.py - "Transient Object API":../../Transience/TransienceInterfaces.py
""" """
from zope.interface import Interface from zope.interface import Interface
......
<dtml-var manage_page_header> <dtml-var manage_page_header>
<dtml-var "manage_form_title(this(), _, <dtml-var "manage_form_title(this(), _,
form_title='Add Temporary Folder', form_title='Add Temporary Folder'
help_product='TemporaryFolder',
help_topic='TemporaryFolder.stx'
)"> )">
<form action="constructTemporaryFolder" method="POST"> <form action="constructTemporaryFolder" method="POST">
......
How Transience Works
The object responsible for managing the expiration of "transient"
objects is the TransientObjectContainer, the class definition for
which is located in
Products.Transience.Transience.TransientObjectContainer. An
instance of this class is found in the default Zope installation at
/temp_folder/session_data.
The TransientObjectContainer (TOC) holds Transient Objects (TOs).
A TO is obtained via its container via a call to
TOC.new_or_existing(key), where "key" is usually the "browser id"
associated with a visitor (See Products.Session.BrowserIdManager).
If the TOC has a "current" TO corresponding to "key", it is
returned.
If the TOC does not have a "current" TO corresponding to "key", (due
to the expiration of the TO or because it never existed in the first
place) a "new" TO is manufactured and returned.
Timeslices
Transience defines the notion of a "timeslice". A "timeslice" is an
integer that represents some "slice" of time, defined by a "period".
For example, if a period is 20 seconds long, three ordered time
slices might be expressed as 0, 20, and 40. The next timeslice
would be 60, and so on. For an absolute time to "belong" to a
timeslice, it would need to be equal to or greater than one
timeslice integer, but less than the subsequent timeslice integer.
Data Structures Maintained by a Transient Object Container
The TOC maintains three important kinds of data structures:
- a "_data" structure, which is an IOBTree mapping a "timeslice"
integer to a "bucket" (see next bullet for definition of bucket).
- One or more "buckets", which are OOBTree objects which map a "key"
(usually browser id) to a TransientObject. Buckets are stored
inside of the "_data" structure. There is a concept of a
"current" bucket, which is the bucket that is contained within the
_data structured with a key equal to the "current" timeslice.
A current bucket must always exist (this is an invariant).
- A "max_timeslice" integer, which is equal to the "largest"
timeslice for which there exists a bucket in the _data structure.
This is an optimization given that key operations against BTrees
can be slow and could cause conflicts (the same could be achieved
via _data.maxKey() otherwise).
When a Transient Object is created via new_or_existing, it is added
to the "current" bucket. As time goes by, the bucket to which the
TO was added ceases to be the "current" bucket. If the transient
object is "accessed" (it is called up out of the TOC via the TOC's
'get' method), it is again moved to the "current" bucket defined by
the current time's timeslice.
During the course of normal operations, a TransientObject will move
from an "old" bucket to the "current" bucket many times, as long as
it continues to be accessed. It is possible for a TransientObject
to never expire, as long as it is called up out of its TOC often
enough.
If a TransientObject is not accessed in the period of time defined by
the TOC's "timeout", it is eventually garbage collected.
How the TransientObjectContainer Determines if a TransientObject is "Current"
All "current" timeslice buckets (as specified by the timeout) are
searched for the transient object, most recent bucket first.
Housekeeping: Finalization, Garbage Collection, and Bucket
Replentishing
The TOC performs "finalization", "garbage collection", and "bucket
replentishing". It typically performs these tasks "in-band"
(although it is possible to do the housekeeping tasks "out of band"
as well: see the methods of the Transient Object Container with
"housekeep" in their names). "In band" housekeeping implies that
the TOC does not maintain a separate thread or process that wakes up
every so often to clean up. Instead, during the course of normal
operations, the TOC opportunistically performs housekeeping functions.
Finalization is defined as optionally calling a function at bucket
expiration time against all transient objects contained within that
bucket. The optional function call is user-defined, but it is
managed by the "notifyDel" method of the TOC.
Garbage collection is defined as deleting "expired" buckets in the
_data structure (the _data structure maps a timeslice to a bucket).
Typically this is done by throwing away one or more buckets in the
_data structure after they expire.
Bucket replentishing is defined as the action of (opportunistically)
creating more buckets to insert into the the _data structure,
replacing ones that are deleted during garbage collection. The act
of deleting a bucket does not necessarily imply that a new bucket
will be immediately created thereafter. We create new buckets in
batches to reduce the possibility of conflicts.
Finalization is attempted on every call to the transience machinery
to make TOs appear to expire "on time". Garbage collection and
replentishment is performed on a somewhat random basis to avoid
unnecessary conflicts.
Goals
- A low number of ZODB conflict errors (which reduce performance).
- Stability.
To Do
- Testing under ZEO.
...@@ -104,15 +104,10 @@ class TransientObjectContainer(SimpleItem): ...@@ -104,15 +104,10 @@ class TransientObjectContainer(SimpleItem):
implements(ItemWithId, implements(ItemWithId,
StringKeyedHomogeneousItemContainer, StringKeyedHomogeneousItemContainer,
TransientItemContainer, TransientItemContainer,
) )
manage_options = ( manage_options = (
{ 'label': 'Manage', {'label': 'Manage', 'action': 'manage_container'},
'action': 'manage_container', {'label': 'Security', 'action': 'manage_access'},
'help': ('Transience', 'Transience.stx')
},
{ 'label': 'Security',
'action': 'manage_access'
},
) )
security = ClassSecurityInfo() security = ClassSecurityInfo()
......
<dtml-var manage_page_header> <dtml-var manage_page_header>
<dtml-var "manage_form_title(this(), _, <dtml-var "manage_form_title(this(), _,
form_title='Add Transient Object Container', form_title='Add Transient Object Container'
help_product='Transience',
help_topic='Transience-add.stx'
)"> )">
<FORM ACTION="constructTransientObjectContainer" METHOD="POST"> <FORM ACTION="constructTransientObjectContainer" METHOD="POST">
......
<dtml-var manage_page_header> <dtml-var manage_page_header>
<dtml-var "manage_tabs(this(), _, <dtml-var "manage_tabs(this(), _,
form_title='Change Transient Object Container', form_title='Change Transient Object Container'
help_product='Transience',
help_topic='Transience-change.stx'
)"> )">
<form action="manage_changeTransientObjectContainer" method="post"> <form action="manage_changeTransientObjectContainer" method="post">
......
<style type="text/css"> <!-- li { margin: 1em } --> </style>
ZopeTestCase API Reference
A nicely rendered version of this document can be found at
http://zope.org/Members/shh/ZopeTestCaseWiki/ApiReference
Module Testing.ZopeTestCase
Top-level package exposing names from contained modules
Constants
folder_name
user_name
user_password
user_role
standard_permissions
portal_name
Functions
hasProduct(name)
installProduct(name, quiet=0)
app()
close(app)
main()
_print(msg)
ZopeDocTestSuite(module=None, **kw)
ZopeDocFileSuite(*paths, **kw)
FunctionalDocTestSuite(module=None, **kw)
FunctionalDocFileSuite(*paths, **kw)
Classes
TestCase
ZopeTestCase
FunctionalTestCase
PortalTestCase
Sandboxed
Functional
WarningsHook
Modules
ZopeLite as Zope
utils
doctest
transaction
Module ZopeLite
Lightweight replacement for the Zope module
Constants
DB
Functions
hasProduct(name)
installProduct(name, quiet=0)
app(connection=None)
sandbox(base=None)
startup()
_print(msg)
Module base
Basic infrastructure for Zope testing
Functions
app()
close(app)
Classes
TestCase
Class TestCase
Base test case for Zope testing
(derived from unittest.TestCase)
Interfaces
implements(IZopeTestCase)
Methods
afterSetUp()
beforeTearDown()
afterClear()
beforeSetUp()
beforeClose()
Module ZopeTestCase
Test case and fixture for Zope testing
Constants
folder_name
user_name
user_password
user_role
standard_permissions
Classes
ZopeTestCase
FunctionalTestCase
Class ZopeTestCase
Base test case for Zope testing
(derived from base.TestCase)
Interfaces
implements(IZopeSecurity)
Methods
setRoles(roles, name=user_name)
setPermissions(permissions, role=user_role)
login(name=user_name)
logout()
Class FunctionalTestCase
Convenience class for functional unit testing
(derived from Functional and ZopeTestCase)
Interfaces
*See base classes*
Methods
*See base classes*
Module PortalTestCase
Test case and fixture for testing CMF-based applications
Constants
portal_name
user_name
user_password
Classes
PortalTestCase
Class PortalTestCase
Base test case for CMF testing
(derived from base.TestCase)
Interfaces
implements(IPortalTestCase, IPortalSecurity)
Methods
getPortal()
createMemberarea(name)
setRoles(roles, name=user_name)
setPermissions(permissions, role='Member')
login(name=user_name)
logout()
Module sandbox
ZODB sandbox support
Classes
Sandboxed
Class Sandboxed
Sandbox support mix-in for xTestCases
Interfaces
*No interfaces*
Methods
*No public methods*
Module functional
Functional testing support
Classes
Functional
Class Functional
Functional testing mix-in for xTestCases
Interfaces
implements(IFunctional)
Methods
publish(path, basic=None, env=None, extra=None, request_method='GET', stdin=None)
Module utils
Utility functions to extend the test environment
Functions
setupCoreSessions(app=None)
setupSiteErrorLog(app=None)
startZServer(number_of_threads=1, log=None)
importObjectFromFile(container, filename, quiet=0)
appcall(func, *args, **kw)
<style type="text/css"> <!-- li { margin: 1em } --> </style>
Functional Testing Readme
The functional testing support of ZopeTestCase was inspired by
Marius Gedminas' work for Zope 3.
Deriving from the 'Functional' mix-in (and an xTestCase) adds a
'publish' method to your test case class. Tests can call
'self.publish(path, basic=None, env=None, extra=None, request_method='GET', stdin=None)',
passing a path and, optionally, basic-auth info and form data.
The path may contain a query string.
'publish' returns an enhanced Response object, that can be queried
for status, response body, headers, etc.
'publish' invokes the ZPublisher machinery just as if the request
had come in through ZServer. This allows for high-level testing
of things like argument marshalling, form validation, and traversal.
Note that the tests have *full access to the ZODB*. This means you
can easily prepare a fixture for 'publish' and/or check the impact
of a publication on the database. This represents a major advantage
over purely URL-based test environments!
Please see the 'testFunctional.py' example test for more.
While the modules are called 'functional.py' in both Zope 3 and
ZopeTestCase, it is current wisdom that such tests are not truly
"functional tests", but rather "integration tests".
True functional tests, in their most-helpful guise as "acceptance
tests", must be able to test the end-user experience. For web
applications this means: browser simulation.
Plone 2 comes with an 'ftests' package combining the functional
testing support of ZopeTestCase with the "mechanize" browser
simulator library: http://wwwsearch.sourceforge.net/mechanize/
(For some version of 2, currently only available from the Plone
CVS HEAD.)
Read the Source
Amen. Read 'functional.py' and 'sandbox.py' if you want to know
what's going on behind the scenes.
<style type="text/css"> <!-- li { margin: 1em } --> </style>
ZopeTestCase Mini How-To
(Still-terse-but-the-Wiki-has-more Version 0.3)
Introduction
*ZopeTestCase* is an attempt to make writing unit and regression tests
in Zope a more rewarding experience. The package deals with all the plumbing
required, and leaves the programmer with writing the tests - and the tests only.
It is built on PyUnit and the Testing package coming with Zope.
ZopeTestCase provides a Zope sandbox to every test. This sandbox comes fully
equipped with ZODB connection, root application object, and REQUEST.
When writing tests you have complete control over Zope, the way you have from a Python
product. The framework is easily customized and can be adapted to virtually every
conceivable test situation.
What you can test with ZTC
- Basically everything. Including security, transactions, sessions, web access, ...
What you cannot test with ZTC
- Web forms and user interaction. This should be left to FunctionalTests.
Prereqs
For an excellent introduction to unit testing read chapter 11 of Mark Pilgrim's
"Dive Into Python.":http://diveintopython.org/unit_testing/index.html
Read about what unit tests are and what they are not in Chris McDonough's
"Unit Testing Zope.":http://zope.org/Members/mcdonc/PDG/UnitTesting
Download and install "ZopeTestCase.":http://zope.org/Members/shh/ZopeTestCase
Be prepared to read the source files, especially the example tests. And the README of course.
What You Get
The ZopeTestCase package consists of the following components:
framework.py
This file must be copied into the individual 'tests' directories (See the README for more).
It locates the Testing and ZopeTestCase packages, detects INSTANCE_HOME installations,
and determines the 'custom_zodb.py' file used to set up the test ZODB. 'framework.py' is
included first thing in every test module.
ZopeLite.py
This module is designed to work like the 'Zope' module, but to load a lot faster.
The speed-up is achieved by not installing Zope products and help files. If your
tests require a product to be installed (most don't actually), you must install
it yourself using the 'installProduct' method. 'ZopeLite' also provides a
'hasProduct' method, that allows to test whether a product can be found along the
products path, i.e. whether it is available to the test instance.
ZopeTestCase.py
This module provides the 'ZopeTestCase' class, which is used as a base class for
all test cases.
A ZopeTestCase sets up a default fixture in the newly started Zope instance.
This fixture consist of a folder, a userfolder inside that folder, and a
user created in that userfolder. The user's role is configured at folder level
and populated with default permissions. Finally, the user is logged in.
This way, once a test runs, a complete and sane Zope "toy" environment is
already in place.
The fixture is destroyed during the tearDown phase and can be switched off
entirely by setting '_setup_fixture=0' in your test case.
The ZopeTestCase class provides a number of hooks that allow you to
adapt the fixture to your needs:
- **'afterSetUp'** is called after the default fixture has been set up. Override this
method to add the objects you intend to test.
*This is clearly the most useful hook. You may ignore the remaining hooks until you
really need them, if ever.*
- **'beforeTearDown'** is called at the start of the tearDown phase. The fixture
is still in place at this point.
- **'afterClear'** is called after the fixture has been destroyed. Note that this
may occur during setUp *and* tearDown. This method must not throw an exception
even when called repeatedly.
Hooks for controlling transactions:
- **'beforeSetUp'** is called before the ZODB connection is opened, at the start of setUp.
The default behaviour of this hook is to call 'transaction.begin()'.
You will rarely want to override this.
- **'beforeClose'** is called before the ZODB connection is closed, at the end of
tearDown. By default this method calls 'transaction.abort()' to discard
any changes made by the test. In some situations you may need to override
this hook and commit the transaction instead. Make sure you really know what
you are doing though.
utils.py
Provides utility methods to extend the test environment:
- **'setupCoreSessions'** creates the Zope sessioning objects in the test ZODB.
- **'setupSiteErrorLog'** creates the error_log object required by ZPublisher.
- **'startZServer'** starts a ZServer thread on the local host. Use this if the
objects you test require URL access to Zope.
- **'importObjectFromFile'** imports a (.zexp) file into a specified container.
Handy for adding "prerolled" components to the sandbox.
These methods must be run at module level. Do not call them from 'afterSetUp' or from tests!
Writing Tests
Generally, writing tests with ZTC is no different from writing "ordinary" Zope code. A complete
Zope environment is made available to every test. The only real difference is that it is not
driven by ZServer + ZPublisher but by the PyUnit TestRunner.
Inside a ZopeTestCase the root application object can be accessed as 'self.app'.
The folder serving as the fixture is available as 'self.folder'. The REQUEST is
reachable as 'self.app.REQUEST'.
1. In your test module create a test case derived from 'ZopeTestCase'.
2. Override 'afterSetUp' to add your own objects to 'self.folder'.
3. Write one or more tests exercising these objects.
How to setup and run your tests is covered in detail by the
"README":http://zope.org/Members/shh/ZopeTestCase/README
The easiest way to start with your own tests is to copy the skeleton test
'testSkeleton.py', and take it from there.
Note that tests are written in unrestricted Python and are not affected by Zope's
security policy. To test the security of individual methods or objects, you must invoke
'restrictedTraverse' or 'validateValue' explicitly!
A simple test may look like::
from Testing import ZopeTestCase
from AccessControl import Unauthorized
class ExampleTest(ZopeTestCase.ZopeTestCase):
def afterSetUp(self):
# Add objects to the workarea
self.folder.addDTMLMethod('doc', file='foo')
def testDocument(self):
self.assertEqual(self.folder.doc(), 'foo')
def testEditDocument(self):
self.folder.doc.manage_edit('bar', '')
self.assertEqual(self.folder.doc(), 'bar')
def testAccessDocument(self):
self.folder.doc.manage_permission('View', ['Manager'])
self.assertRaises(Unauthorized,
self.folder.restrictedTraverse, 'doc')
Read the Examples
Please study the example tests for more:
- **'testSkeleton.py'** represents the simplest possible ZopeTestCase. The module contains all
the plumbing required. It is recommended that you copy this file to start your own tests.
- **'testPythonScript.py'** tests a PythonScript object in the default fixture.
It demonstrates how to manipulate the test user's roles and permissions and how
security is validated.
- **'testShoppingCart.py'** tests the ShoppingCart example. This test
uses Sessions and shows how to test a TTW Zope application.
- **'testFunctional.py'** demonstrates the new functional testing features.
Tests may call 'self.publish()' to simulate URL calls to the ZPublisher.
- **'testWebserver.py'** starts up an HTTP ZServer thread and tests URL access to it. This
test is an example for explicit transaction handling and shows how to use ZODB
sandboxes to further increase isolation between individual tests.
- **'testZopeTestCase.py'** tests the ZopeTestCase class itself. May be of interest to the
investigative types.
- **'testPortalTestCase.py'** contains an equivalent test suite for the PortalTestCase
base class.
- **'testZODBCompat.py'** tests various aspects of ZODB behavior in a ZopeTestCase environment.
Shows things like cut/paste, import/export, and that _v_ and _p_ variables survive
transaction boundaries.
Read the Source
The source files are well documented and an overall worthy read &lt;wink&gt;:
- The ZopeTestCase class is defined in file 'ZopeTestCase.py'.
- The interfaces implemented by this class are documented in 'interfaces.py'.
- All names exported by the ZopeTestCase package are listed in '__init__.py'.
Resources
A Wiki with all the documentation:
"ZopeTestCaseWiki":http://zope.org/Members/shh/ZopeTestCaseWiki
Slides of my talk at EuroPython 2003:
"UnitTestingZope":http://zope.org/Members/shh/UnitTestingZope.pdf
A testrunner with INSTANCE_HOME support:
"TestRunner":http://zope.org/Members/shh/TestRunner
Related
"PyUnit":http://pyunit.sf.net (Steve Purcell)
"WebUnit":http://mechanicalcat.net/tech/webunit (Richard Jones) and
"WebUnit":http://webunit.sf.net (Steve Purcell)
"ZUnit":http://zope.org/Members/lalo/ZUnit (Lalo Martins)
"FunctionalTests":http://zope.org/Members/tseaver/FunctionalTests (Tres Seaver)
"WebsiteLoadTest":http://zope.org/Members/ajung/WebsiteLoadTest (Andreas Jung)
Contact
Feel free to send bug reports, feature requests, etc to stefan at epy.co.at.
<style type="text/css"> <!-- li { margin: 1em } --> </style>
PortalTestCase Readme
The PortalTestCase class is a close relative of the ZopeTestCase
class. It was devised at the Plone Castle Sprint to form the base of an
integration testing framework for Plone 2.0. Thanks to Gidon Friedman
and Godefroid Chapelle for their collaboration.
Much of what is true for ZopeTestCase is true for PortalTestCase as well:
* PortalTestCase handles the ZODB connection, transaction, and
application object; and it provides a REQUEST.
* PortalTestCase sets up a user folder and a user.
* PortalTestCase provides the same hooks as ZopeTestCase.
* PortalTestCase implements the same security interfaces as
ZopeTestCase.
What's different?
* PortalTestCase is designed for testing CMF-based applications.
* The fixture is slightly more complex, consisting of a portal object,
a userfolder + user, and the user's memberarea.
* For flexibility, the portal is *not* created by the base class but
must be provided by the user (typically a derived xTestCase) of the
PortalTestCase base class.
* Subclasses will have to override 'getPortal' to return the object
serving as the portal.
* The portal will however be configured by the machinery which means
creating a user and a fresh memberarea for every test.
* Subclasses may override 'createMemberarea' to provide customized
and/or more lightweight memberareas to the tests. This can improve
performance quite significantly.
Feature Comparison:
ZopeTestCase
* 1 user + 1 role
* Folder contains user folder and role definition
* Folder also serves as workarea
* User is logged in
* Provides attributes::
self.app
self.app.REQUEST
self.folder
self.folder.acl_users
PortalTestCase
* 1 user + 'Member' role
* Portal contains user folder and role definition
* User's home folder serves as workarea
* User is logged in
* Provides attributes::
self.app
self.app.REQUEST
self.portal
self.portal.acl_users
self.folder
Read the Source
As always, I recommend to look at the source code of both
'ZopeTestCase.py' and 'PortalTestCase.py' for all the details you may need.
Interface documentation can be found in 'interfaces.py'.
The test framework shipping with Plone 2.0 is a good example of how the
PortalTestCase class can be put to use.
<style type="text/css"> <!-- li { margin: 1em } --> </style>
ZopeTestCase Readme
The ZopeTestCase package has been developed in the hope that it will make
testing Zope packages more convenient. It has features to support various
scenarios from unit-testing individual components inside a "toy" environment
to running regression tests against live ZEO servers.
To add a test suite to a Zope package:
1. Make a 'tests' subdirectory.
2. Create an (empty) '__init__.py' in 'tests' to make it a package.
Once a test suite has been set up, you can add test modules:
1. Create a file with a name matching 'test*.py'.
2. Import the 'ZopeTestCase' package as in 'from Testing import ZopeTestCase'
and define one or more subclasses of 'ZopeTestCase.ZopeTestCase'.
3. Define methods for the test classes. Each method's name must start
with 'test'. It should test one small case, preferably using a PyUnit
assertion method. Here's a minimal example::
class ExampleTest(ZopeTestCase.ZopeTestCase):
def testAddition(self):
self.assertEqual(1+1, 2)
4. You can add 'afterSetUp' and 'beforeTearDown' methods that are automatically
called after the fixture has been set up and before the fixture is destroyed
respectively.
Note that there is a skeleton test suite named 'testSkeleton.py' that you
may copy into your 'tests' directory and take it from there.
See the sample tests in the 'ZopeTestCase' directory for details on writing
your own tests.
<style type="text/css"> <!-- li { margin: 1em } --> </style>
Default Fixture
- **'self.app'** is the root application object of the test ZODB (contains Control_Panel, ...)
Note that a ZODB connections has already been opened and a transaction begun at this point.
- **'self.app.REQUEST'** is the request object. Note that the REQUEST is rather minimal because
ZPublisher is not involved when running tests, and as such many REQUEST variables are never
set. Feel free to add to the REQUEST whatever your tests require.
- **'self.folder'** is the work area. This folder will be created anew for each test and thrown
away once the test has finished. The name of the folder is 'test_folder_1_'. You should
use the 'ZopeTestCase.folder_name' constant when you need the folder's name. 'self.folder' is a
reference to the object at 'self.app[folder_name]'.
A default role definition ('ZopeTestCase.user_role') is added to the folder, and a list of
permissions ('ZopeTestCase.standard_permissions') is assigned to the role.
- **'self.folder.acl_users'** is the user folder providing a security context to the work area.
A default user account is added to the user folder with name 'test_user_1_' and password 'secret'.
You should use the 'ZopeTestCase.user_name' constant when you need the user's name, the
'ZopeTestCase.user_password' constant when you need the user's password.
The default user has a single role, 'ZopeTestCase.user_role'.
At the end of the setup process the default user is logged in, and the 'afterSetUp' hook is called.
Security API
- **'self.setRoles(roles, name=user_name)'** allows to change the roles assigned to a user.
If the 'name' argument is omitted, changes the roles of the default user.
- **'self.setPermissions(permissions, role=user_role)'** allows to change the permissions
assigned to a role. If the 'role' argument is omitted, changes the permissions of the
default role.
- **'self.login(name=user_name)'** allows to log in as a specified user.
If the 'name' argument is omitted, logs in as the default user.
- **'self.logout()'** allows to log out and become 'Anonymous User'.
Testing Security
- **'ob.restrictedTraverse("attr")'** is a simple way to check whether the currently logged in user is
allowed to access attribute 'attr' of object 'ob'.
- **'getSecurityManager().validate(None, ob, "attr", ob.attr)'** uses the security manager to do the same.
The convenience method 'getSecurityManager().validateValue(ob.attr)' will no longer work
in Zope 2.8.
Also see the 'testPythonScript.py' example test.
Note that you have the entire Zope security API at your disposal to further refine your fixture.
E.g. to add another user call 'self.folder.acl_users.userFolderAddUser("user2", "secret", ["role2"], [])'.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment