# HG changeset patch # User Aurelien Campeas # Date 1271179177 -7200 # Node ID 67dbd07a05f346216dc63a5e5a7e3515db969d02 # Parent 369b8aff535be4693b7b5952e9787555c1e6e762 [doc/book] expand tesing material diff -r 369b8aff535b -r 67dbd07a05f3 devtools/testlib.py --- 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' diff -r 369b8aff535b -r 67dbd07a05f3 doc/book/en/development/testing.rst --- 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: +