doc/book/en/development/testing.rst
branchstable
changeset 5394 105011657405
parent 5393 875bdc0fe8ce
child 5395 e0ab7433e640
--- a/doc/book/en/development/testing.rst	Fri Apr 23 17:07:55 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,258 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Tests
-=====
-
-Unit tests
-----------
-
-The *CubicWeb* framework provides the `CubicWebTC` test base class in
-the module `cubicweb.devtools.testlib`.
-
-Tests shall be put into the mycube/test directory. Additional test
-data shall go into mycube/test/data.
-
-It is much advised to write tests concerning entities methods, hooks
-and operations, security. The CubicWebTC base class has convenience
-methods to help test all of this.
-
-.. note::
-
-  In the realm of views, there is not much to do but check that the
-  views are valid XHTML.  See :ref:`automatic_views_tests` for
-  details. Integration of CubicWeb tests with UI testing tools such as
-  `selenium`_ are currently under invesitgation.
-
-.. _selenium: http://seleniumhq.org/projects/ide/
-
-Most unit tests need a live database to work against. This is achieved
-by CubicWeb using automatically sqlite (bundled with Python, see
-http://docs.python.org/library/sqlite3.html) as a backend.
-
-The database is stored in the mycube/test/tmpdb,
-mycube/test/tmpdb-template files. If it does not (yet) exists, it will
-be built automatically when the test suit starts.
-
-.. warning::
-
-  Whenever the schema changes (new entities, attributes, relations)
-  one must delete these two files. Changes concerned only with entity
-  or relation type properties (constraints, cardinalities,
-  permissions) and generally dealt with using the
-  `sync_schema_props_perms()` fonction of the migration environment
-  need not a database regeneration step.
-
-Unit test by example
-````````````````````
-
-We start with an example extracted from the keyword cube (available
-from http://www.cubicweb.org/project/cubicweb-keyword).
-
-.. sourcecode:: python
-
-    from cubicweb.devtools.testlib import CubicWebTC
-    from cubicweb import ValidationError
-
-    class ClassificationHooksTC(CubicWebTC):
-
-        def setup_database(self):
-            req = self.request()
-            group_etype = req.execute('Any X WHERE X name "CWGroup"').get_entity(0,0)
-            c1 = req.create_entity('Classification', name=u'classif1',
-                                   classifies=group_etype)
-            user_etype = req.execute('Any X WHERE X name "CWUser"').get_entity(0,0)
-            c2 = req.create_entity('Classification', name=u'classif2',
-                                   classifies=user_etype)
-            self.kw1 = req.create_entity('Keyword', name=u'kwgroup', included_in=c1)
-            self.kw2 = req.create_entity('Keyword', name=u'kwuser', included_in=c2)
-
-        def test_cannot_create_cycles(self):
-            # direct obvious cycle
-            self.assertRaises(ValidationError, self.kw1.set_relations,
-                              subkeyword_of=self.kw1)
-            # testing indirect cycles
-            kw3 = self.execute('INSERT Keyword SK: SK name "kwgroup2", SK included_in C, '
-                               'SK subkeyword_of K WHERE C name "classif1", K eid %s'
-                               % self.kw1.eid).get_entity(0,0)
-            self.kw1.set_relations(subkeyword_of=kw3)
-            self.assertRaises(ValidationError, self.commit)
-
-The test class defines a `setup_database` method which populates the
-database with initial data. Each test of the class runs with this
-pre-populated database.
-
-The test case itself checks that an Operation does it job of
-preventing cycles amongst Keyword entities.
-
-You can see an example of security tests in the
-:ref:`adv_tuto_security`.
-
-It is possible to have these tests run continuously using `apycot`_.
-
-.. _apycot: http://www.logilab.org/project/apycot
-
-Managing connections or users
-+++++++++++++++++++++++++++++
-
-Since unit tests are done with the SQLITE backend and this does not
-support multiple connections at a time, you must be careful when
-simulating security, changing users.
-
-By default, tests run with a user with admin privileges. This
-user/connection must never be closed.
-
-Before a self.login, one has to release the connection pool in use
-with a self.commit, self.rollback or self.close.
-
-The `login` method returns a connection object that can be used as a
-context manager:
-
-.. sourcecode:: python
-
-   with self.login('user1') as user:
-       req = user.req
-       req.execute(...)
-
-On exit of the context manager, either a commit or rollback is issued,
-which releases the connection.
-
-When one is logged in as a normal user and wants to switch back to the
-admin user without committing, one has to use
-self.restore_connection().
-
-Usage with restore_connection:
-
-.. sourcecode:: python
-
-    # execute using default admin connection
-    self.execute(...)
-    # I want to login with another user, ensure to free admin connection pool
-    # (could have used rollback but not close here
-    # we should never close defaut admin connection)
-    self.commit()
-    cnx = self.login('user')
-    # execute using user connection
-    self.execute(...)
-    # I want to login with another user or with admin user
-    self.commit();  cnx.close()
-    # restore admin connection, never use cnx = self.login('admin'), it will return
-    # the default admin connection and one may be tempted to close it
-    self.restore_connection()
-
-.. warning::
-
-   Do not use the references kept to the entities created with a
-   connection from another !
-
-Email notifications tests
--------------------------
-
-When running tests potentially generated e-mails are not really sent
-but is found in the list `MAILBOX` of module
-`cubicweb.devtools.testlib`.
-
-You can test your notifications by analyzing the contents of this list, which
-contains objects with two attributes:
-
-* `recipients`, the list of recipients
-* `msg`, object email.Message
-
-Let us look at simple example from the ``blog`` cube.
-
-.. sourcecode:: python
-
-    from cubicweb.devtools.testlib import CubicWebTC, MAILBOX
-
-    class BlogTestsCubicWebTC(CubicWebTC):
-        """test blog specific behaviours"""
-
-        def test_notifications(self):
-            req = self.request()
-            cubicweb_blog = req.create_entity('Blog', title=u'cubicweb',
-                                description=u'cubicweb is beautiful')
-            blog_entry_1 = req.create_entity('BlogEntry', title=u'hop',
-                                             content=u'cubicweb hop')
-            blog_entry_1.set_relations(entry_of=cubicweb_blog)
-            blog_entry_2 = req.create_entity('BlogEntry', title=u'yes',
-                                             content=u'cubicweb yes')
-            blog_entry_2.set_relations(entry_of=cubicweb_blog)
-            self.assertEquals(len(MAILBOX), 0)
-            self.commit()
-            self.assertEquals(len(MAILBOX), 2)
-            mail = MAILBOX[0]
-            self.assertEquals(mail.subject, '[data] hop')
-            mail = MAILBOX[1]
-            self.assertEquals(mail.subject, '[data] yes')
-
-.. _automatic_views_tests:
-
-Automatic views testing
------------------------
-
-This is done automatically with the AutomaticWebTest class. At cube
-creation time, the mycube/test/test_mycube.py file contains such a
-test. The code here has to be uncommented to be usable, without
-further modification.
-
-The ``auto_populate`` method uses a smart algorithm to create
-pseudo-random data in the database, thus enabling the views to be
-invoked and tested.
-
-Depending on the schema, hooks and operations constraints, it is not
-always possible for the automatic auto_populate to proceed.
-
-It is possible of course to completely redefine auto_populate. A
-lighter solution is to give hints (fill some class attributes) about
-what entities and relations have to be skipped by the auto_populate
-mechanism. These are:
-
-* `no_auto_populate`, may contain a list of entity types to skip
-* `ignored_relations`, may contain a list of relation types to skip
-* `application_rql`, may contain a list of rql expressions that
-  auto_populate cannot guess by itself; these must yield resultsets
-  against which views may be selected.
-
-
-Test APIS
----------
-
-Using Pytest
-````````````
-
-The `pytest` utility (shipping with `logilab-common`_, which is a
-mandatory dependency of CubicWeb) extends the Python unittest
-functionality and is the preferred way to run the CubicWeb test
-suites. Bare unittests also work the usual way.
-
-.. _logilab-common: http://www.logilab.org/project/logilab-common
-
-To use it, you may:
-
-* just launch `pytest` in your cube to execute all tests (it will
-  discover them automatically)
-* launch `pytest unittest_foo.py` to execute one test file
-* launch `pytest unittest_foo.py bar` to execute all test methods and
-  all test cases whose name contain `bar`
-
-Additionally, the `-x` option tells pytest to exit at the first error
-or failure. The `-i` option tells pytest to drop into pdb whenever an
-exception occurs in a test.
-
-When the `-x` option has been used and the run stopped on a test, it
-is possible, after having fixed the test, to relaunch pytest with the
-`-R` option to tell it to start testing again from where it previously
-failed.
-
-Using the `TestCase` base class
-```````````````````````````````
-
-The base class of CubicWebTC is logilab.common.testlib.TestCase, which
-provides a lot of convenient assertion methods.
-
-.. autoclass:: logilab.common.testlib.TestCase
-   :members:
-
-CubicWebTC API
-``````````````
-.. autoclass:: cubicweb.devtools.testlib.CubicWebTC
-   :members: