[doc/book] expand tesing material stable
authorAurelien Campeas <aurelien.campeas@logilab.fr>
Tue, 13 Apr 2010 19:19:37 +0200
branchstable
changeset 5229 67dbd07a05f3
parent 5228 369b8aff535b
child 5230 cd033d2f4229
[doc/book] expand tesing material
devtools/testlib.py
doc/book/en/development/testing.rst
--- a/devtools/testlib.py	Tue Apr 13 19:18:06 2010 +0200
+++ b/devtools/testlib.py	Tue Apr 13 19:19:37 2010 +0200
@@ -130,18 +130,17 @@
 
 class CubicWebTC(TestCase):
     """abstract class for test using an apptest environment
+    attributes:
 
-    attributes:
-    `vreg`, the vregistry
-    `schema`, self.vreg.schema
-    `config`, cubicweb configuration
-    `cnx`, dbapi connection to the repository using an admin user
-    `session`, server side session associated to `cnx`
-    `app`, the cubicweb publisher (for web testing)
-    `repo`, the repository object
-
-    `admlogin`, login of the admin user
-    `admpassword`, password of the admin user
+    * `vreg`, the vregistry
+    * `schema`, self.vreg.schema
+    * `config`, cubicweb configuration
+    * `cnx`, dbapi connection to the repository using an admin user
+    * `session`, server side session associated to `cnx`
+    * `app`, the cubicweb publisher (for web testing)
+    * `repo`, the repository object
+    * `admlogin`, login of the admin user
+    * `admpassword`, password of the admin user
 
     """
     appid = 'data'
--- a/doc/book/en/development/testing.rst	Tue Apr 13 19:18:06 2010 +0200
+++ b/doc/book/en/development/testing.rst	Tue Apr 13 19:19:37 2010 +0200
@@ -6,27 +6,90 @@
 .. toctree::
    :maxdepth: 1
 
-
 Unit tests
 ----------
 
-*CubicWeb* framework provides essentially two Python test classes in the
-module `cubicweb.devtools.apptest`:
+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/
 
-* `EnvBasedTC`, to simulate a complete environment (web + repository)
-* `RepositoryBasedTC`, to simulate a repository environment only
+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::
 
-Those two classes almost have the same interface and offer numerous
-methods to write tests rapidly and efficiently.
+  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
+````````````````````
 
-XXX FILLME describe API
+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)
 
-In most of the cases, you will inherit `EnvBasedTC` to write Unittest or
-functional tests for your entities, views, hooks, etc...
+        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)
 
-XXX pytestconf.py & options (e.g --source to use a different db
-backend than sqlite)
+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.
+
+
+XXX ref to advanced use case
+XXX apycot plug
 
 Managing connections or users
 +++++++++++++++++++++++++++++
@@ -62,23 +125,78 @@
     # the default admin connection and one may be tempted to close it
     self.restore_connection()
 
-Do not use the references kept to the entities created with a connection from another.
+.. warning::
 
+   Do not use the references kept to the entities created with a
+   connection from another !
+
+XXX the new context manager ?
 
 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.apptest`.
-This list is reset at each test *setUp* (by the setUp of classes `EnvBasedTC`
-and `RepositoryBasedTC`).
 
+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.
 
-Automatic testing
------------------
-XXXFILLME
+.. 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.
+
+XXX more to come
+
+
+Using Pytest
+````````````
+
+.. automodule:: logilab.common.testlib
+.. autoclass:: logilab.common.testlib.TestCase
+   :members:
+
+XXX pytestconf.py & options (e.g --source to use a different db
+backend than sqlite)
+
+CubicWebTC API
+``````````````
+.. autoclass:: cubicweb.devtools.testlib.CubicWebTC
+   :members:
+