= Testing =
"A bug is a test case you haven't written yet" [[BR]]
"Unit Tests allow merciless [http://diveintopython.org/refactoring/refactoring.html refactoring]"
This page defines what our current approach versus our [wiki:BluePrintTesting BluePrint for future options]
Test-Driven Development is a programming styles which says that you 1st write your test cases (from the [BluePrints specs]) & then proceed to make them pass.
Can pre-populate the database with random data using [http://groups.google.com/group/web2py/browse_thread/thread/4b2e5ed166220ba5# gluon.contrib.populate]
[wiki:InstallationGuidelinesDeveloperTesting]
== Functional Tests ==
Building the Right Code
We have integrated [http://seleniumhq.org/projects/core Selenium Core] into {{{/static/selenium}}} so that Functional Tests can be run (via 'Test' menu option visible to Admins).
Additional functions (e.g. Random) are added to:
{{{
/static/selenium/core/scripts/user-extensions.js
}}}
!ToDo: create a {{{HandleResults.py}}} for storing results (to make visible to CI):
* e.g. Convert this one from PHP: http://wiki.openqa.org/display/SEL/Integrating+Selenium+And+CruiseControl.Net
* e.g. Extract from [http://jrandolph.com/selenium-plone/selenium-0.3rc2-plone.zip PloneTool]'s {{{FunctionalTestTool.py}}}
Tests can be developed using [http://seleniumhq.org/projects/ide Selenium IDE], if desired.
If desired they can be maintained in a Python format using [http://joker.linuxstuff.pl/documentation/make_selenium make_selenium.py]. HTML tests run by !TestRunner are in {{{/static/selenium/tests}}}. Python format tests are in {{{/static/selenium/src}}}. Convert between these using:
{{{
python make_selenium.py src tests
python make_selenium.py -p tests src
}}}
Hints on improving the stability of Selenium tests:
* http://googletesting.blogspot.com/2009/06/my-selenium-tests-arent-stable.html
== Unit Tests ==
Building the Code Right
[http://seleniumhq.org/projects/remote-control Selenium RC] is great due to ability to handle !JavaScript & also due to having an [http://seleniumhq.org/projects/ide IDE] for generating them (export as Python).[[BR]]
The IDE output needs to be [http://groups.google.com/group/web2py/msg/d8c9fd6008029f6b modified] to work with Web2Py.[[BR]]
NB Custom functions (e.g. for Random) cannot be shared with the Functional Tests (custom=JS) but the rest of the tests can be.[[BR]]
These tests are stored in {{{/tests}}}.[[BR]]
!ToDo: Port the storeRandom function from JS to Python:
{{{
import random
print "test_%i@xxxxxxxx" % random.randint(1, 10000)
}}}
!ToDo: Investigate how we can test multiple browsers.
[http://cherrypy.org CherryPy]'s [http://cherrypy.org/browser/trunk/cherrypy/test/webtest.py WebTest] is good for in-process testing & can be run from a browser-less server(easier for CI-integration).[[BR]]
These tests are stored in {{{/tests/webtest}}}.[[BR]]
NB These are a work-in-progress...need to enable access to Web2Py environment (db, etc) using:
{{{
from gluon.shell import exec_environment
env=exec_environment('the_model_file.py')
}}}
Or could write as a 'Controller' & call from CLI:
{{{
python web2py.py -S appname -M -R yourscript.py
}}}
== Doc Tests ==
Agile documentation which can be run using Web2Py's Admin UI.
* http://www.python.org/doc/2.6/library/doctest.html
* e.g. http://127.0.0.1:8000/admin/default/test/sahana/default.py
To extend these to web applications, we have a module which uses [http://code.google.com/p/wsgi-intercept wsgi_intercept] & [http://cherrypy.org CherryPy]'s [http://cherrypy.org/browser/trunk/cherrypy/test/webtest.py WebTest]: {{{modules/s3_test.py}}} [[BR]]
This can be used from Controllers like:
{{{
def login():
""" Login
>>> from applications.sahana.modules.s3_test import WSGI_Test
>>> test=WSGI_Test(db)
>>> '200 OK' in test.getPage('/sahana/%s/login' % module)
True
>>> test.assertHeader("Content-Type", "text/html")
>>> test.assertInBody('Login')
"""
}}}
This works fine,although if an assert fails then the UI gets stuck :/ [[BR]]
The 'db' access part isn't yet working.
Note that Web2Py uses a big doctest at the end of each file: {{{def test_all()}}}
== Continuous Integration ==
We are starting to use the Trac-integrated [http://bitten.edgewall.org Bitten] to monitor code quality.
!ToDo: Write a step to parse/store the results of Selenium's {{{HandleResults.py}}}
{{{
}}}
!ToDo: Amend so that it can find the {{{gluon}}} module (or configure to not follow this dependency):[[BR]]
{{{ImportError: Unable to find module for modules/validators.py in /tmp/bittenA787wC/build_Trunk_1}}}[[BR]]
!ToDo: Fix Windows path (NB plain 'bzr' fails too, even if we're in the folder up from that):
{{{F: 1: No module named /var/www/trac/sahana3/bzr}}}
We need to write a {{{build/test-results.xml}}} for this one (& it also wants a {{{setup.py}}}?):
{{{
}}}
This one is pointless for us as we don't build anything using a {{{setup.py}}}:
{{{
}}}
----
DeveloperGuidelines