=========================
Zope 3 Functional Testing
=========================

How to run Zope 3 functional tests
----------------------------------

In the top-level directory, run "python test.py -f".  If you've read
UNITTEST.txt you'll notice that the same script is used, but with an
additional argument '-f'.  That's because in Zope 3 functional tests are
just a special case of unit tests.  The rest of test.py options work as
well, for example you can use "python test.py -fpv" to get a nice progress
indicator.  For information about all options run "python test.py -h".

If your Zope 3 doesn't yet have a products.zcml, create one by
copying products.zcml.in to products.zcml.

Zope Functional Testing
-----------------------

Functional tests live in directories called "ftests" all over the source
tree.  They use the same PyUnit framework as unit tests, and I recommend
reading UNITTEST.txt and familiarizing with unit tests before moving on to
functional tests.

Functional tests differ from unit tests in that nearly all ZCML configuration
files are parsed and a virtual in-memory storage is created before running
them.  Any changes made to the storage will be discarded at the end of the
test.

What Functional Tests Are
-------------------------

Functional tests are meant to test more than just a single unit of code.
While unit tests make sure that all components work as designed, functional
tests ensure that those components are connected correctly, and that the
system works as a whole.

Writing Functional Tests
------------------------

Functional tests in Zope 3 use the same conventions as unit tests, but with
the following differences:

- Functional test modules live in directories called 'ftests' or
  modules name 'ftests.py'.

- Functional test cases inherit from
  `zope.testing.functional.FunctionalTestCase` or
  `zope.testing.functional.BrowserTestCase` instead of
  `unittest.TestCase`.

- All global services, components etc. defined in assorted configure.zcml
  are available during test run time.

- A volatile in-memory storage with an empty root folder and all essential
  services is available and is automatically cleaned after every test.
  The test code can access and modify the root folder by calling
  `self.getRootFolder()`.

- Browser requests can be emulated by inheriting from
  `BrowserTestCase` and calling `self.publish()`.  See the docstring
  in src/zope/app/tests/functional.py for detailed information.  Here
  are a couple of simple examples::

     response = self.publish('/folder/object')
     self.assertEquals(response.getStatus(), 200)
     self.assert_(response.getBody().find("some text") != -1)

     response = self.publish(
         '/something/action.html',
         basic='username:password',
         form={'id': u'foo', 'UPDATE_SUBMIT': u'Submit'})
     self.assertEquals(response.getStatus(), 302)
     self.assertEquals(response.getHeader('Location'),
                       'http://localhost/something.html')

- If you want to make changes made directly through access to
  `self.getRootFolder()` available to an emulated request, make sure
  to commit the transaction.  Here's how you do it::

    from transaction import get_transaction
    get_transaction().commit()

- Functional tests should not change any global registries.  In
  particular, functional unit test cases should not inherit from
  `zope.testing.cleanup.CleanUp` or any of the `PlacelessSetup`
  classes that inherit from `CleanUp`.
