[Cubicweb] Simple forms unit-testing

Adrien Di Mascio adrien.dimascio at logilab.fr
Fri Nov 26 09:35:00 CET 2010


Hi,

In one of my projects, I've implemented a somewhat simple API to test 
the form rendering and submission. Let me tell immediately that this is 
**pure python / off-browser** testing and therefore means that this 
won't test any javascript / css / user interaction.

Using a lot of of forms in my application, my goal here was to be able 
to test automatically :

- visible fields (i.e. 'hidden', 'visible' fields in uicfg)
- fields order
- redirect urls after form submission

Here are a few examples of what it looks like:

     def test_company_creation_redirectpath(self):
         # 1/ build a creation form for Company entity type
         form = self.creation_form('Company')
         # 2/ set a few values
         form.set_value('name', u'Logilab')
         form.set_value('phone', u'01.02.03.04.05')
         # 3/ submit and check redirection
         self.assertRedirectsTo(form, '/Company/Logilab')

     def test_company_edition_redirectpath(self):
         company = self.create_entity('Company', name=u'Logilab')
         # 1/ get the edition form for the `company` entity
         form = self.edition_form(company)
         # 2/ set a few values
         form.set_value('phone', u'01.02.03.04.05')
         # 3/ submit and check redirection
         self.assertRedirectsTo(form, '/Company/Logilab')

     def test_company_form_visible_fields(self):
         # 1/ build a creation form for Company entity type
         form = self.creation_form('Company')
         # 2/ check order of visible fields
         self.assertEqual(form.visible_fields(),
                          ['name', 'website', 'phone'])
         self.assertItemsEqual(form.edited_fields(),
                               ('__type', 'logo-subject',
                                'name-subject', 'website-subject',
                                'phone-subject'))

     def test_company_inlined_forms(self):
         form = self.creation_form('Company')
         form.set_value('name', u'Logilab')
         # get the inlined form for the 'logo' relation
         logo_form = form.inlined_forms('logo')[0]
         self.assertItemEqual(logo_form.edited_fields(),
                              ('__type', 'data-subject',
                               'logo-object'))
         self.assertEqual(logo_form.visible_fields(), ['data'])
         logo_form.set_value('data',
                             file(self.datapath('logo.jpg')))
         self.assertRedirectsTo(form, '/Company/Logilab')
         # database now contains a new company with a logo, more
         # tests can be done on submitted data


The underlying mechanism is fairly simple :

- the object returned by `creation_form()` and `edition_form()`
   methods is a wrapper around the CW form object (which is available
   as a `cw_form` attribute)
- this object has a few helper methods such as `edited_fields()`,
   `set_value()`, `get_value()`, etc.
- this object holds also the lxml tree corresponding to the actual HTML
- `get_value` and `set_value` methods use the lxml tree to get / set
   input values
- form submission consists in three steps :
   1. using lxml's form_values() method to build a dict-like object
      based on actual input values
   2. building a CubicWeb's request object around that dict-like object
   3. using ctrl_publish() to process the request and go through the
      edit controller chain

As usual, any thoughts on that ? Any interest outside my project ? If 
so, is the API clear enough ? Should it be integrated in CubicWeb ?

-- 
Adrien Di Mascio - LOGILAB, Paris (France).
Tél: 01.45.32.03.12
Formations - http://www.logilab.fr/formations
Développements - http://www.logilab.fr/services
Gestion de connaissances - http://www.cubicweb.org/



More information about the Cubicweb mailing list