summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/reference.rst1
-rw-r--r--doc/reference/cmdline.rst4
-rw-r--r--doc/reference/testing.rst73
-rw-r--r--openerp/addons/base/tests/test_xmlrpc.py16
-rw-r--r--openerp/tests/common.py42
5 files changed, 106 insertions, 30 deletions
diff --git a/doc/reference.rst b/doc/reference.rst
index bf0ad5d6d1a..a3dd9783ff8 100644
--- a/doc/reference.rst
+++ b/doc/reference.rst
@@ -12,6 +12,7 @@ Reference
reference/module
reference/cmdline
reference/security
+ reference/testing
reference/http
reference/qweb
diff --git a/doc/reference/cmdline.rst b/doc/reference/cmdline.rst
index 140405d0037..e3f2952c5d3 100644
--- a/doc/reference/cmdline.rst
+++ b/doc/reference/cmdline.rst
@@ -38,6 +38,10 @@ Running the server
(:file:`{$HOME}/.openerp_serverrc` by default, overridable using
:option:`-c`)
+.. option:: --test-enable
+
+ runs tests after installing modules
+
.. _reference/cmdline/scaffold:
Scaffolding
diff --git a/doc/reference/testing.rst b/doc/reference/testing.rst
new file mode 100644
index 00000000000..2676c2b4084
--- /dev/null
+++ b/doc/reference/testing.rst
@@ -0,0 +1,73 @@
+.. _reference/testing:
+
+===============
+Testing Modules
+===============
+
+Odoo provides support for testing modules using unittest2_.
+
+To write tests, simply define a ``tests`` sub-package in your module, it will
+be automatically inspected for test modules. Test modules should have a name
+starting with ``test_`` and should be imported from ``tests/__init__.py``,
+e.g.
+
+.. code-block:: text
+
+ your_module
+ |-- ...
+ `-- tests
+ |-- __init__.py
+ |-- test_bar.py
+ `-- test_foo.py
+
+and ``__init__.py`` contains::
+
+ from . import test_foo, test_bar
+
+.. note:: test modules which are not imported from ``tests/__init__.py`` will
+ not be run
+
+The test runner will simply run any test case, as described in the official
+`unittest documentation`_, but Odoo provides a number of utilities and helpers
+related to testing Odoo content (modules, mainly):
+
+.. autoclass:: openerp.tests.common.TransactionCase
+ :members: browse_ref, ref
+
+.. autoclass:: openerp.tests.common.SingleTransactionCase
+ :members: browse_ref, ref
+
+By default, tests are run once right after the corresponding module has been
+installed. Test cases can also be configured to run after all modules have
+been installed, and not run right after the module installation:
+
+.. autofunction:: openerp.tests.common.at_install
+
+.. autofunction:: openerp.tests.common.post_install
+
+The most common situation is to use
+:class:`~openerp.tests.common.TransactionCase` and test a property of a of a
+model in each method::
+
+ class TestModelA(common.TransactionCase):
+ def test_some_action(self):
+ record = self.env['model.a'].create({'field': 'value'})
+ record.some_action()
+ self.assertEqual(
+ record.field,
+ expected_field_value)
+
+ # other tests...
+
+Running tests
+-------------
+
+Tests are automatically run when installing or updating modules if
+:option:`--test-enable <odoo.py --test-enable>` was enabled when starting the
+Odoo server.
+
+As of Odoo 8, running tests outside of the install/update cycle is not
+
+
+.. _unittest2: http://pypi.python.org/pypi/unittest2
+.. _unittest documentation: https://docs.python.org/2/library/unittest.html
diff --git a/openerp/addons/base/tests/test_xmlrpc.py b/openerp/addons/base/tests/test_xmlrpc.py
index 1d899866ab1..d8e6528bc18 100644
--- a/openerp/addons/base/tests/test_xmlrpc.py
+++ b/openerp/addons/base/tests/test_xmlrpc.py
@@ -1,18 +1,16 @@
# -*- coding: utf-8 -*-
-import time
-import unittest2
-import xmlrpclib
-
import openerp.tests.common
DB = openerp.tests.common.DB
class test_xmlrpc(openerp.tests.common.HttpCase):
+ at_install = False
+ post_install = True
def test_01_xmlrpc_login(self):
""" Try to login on the common service. """
uid = self.xmlrpc_common.login(DB, 'admin', 'admin')
- self.assertTrue(uid == 1)
+ self.assertEqual(uid, 1)
def test_xmlrpc_ir_model_search(self):
""" Try a search on the object service. """
@@ -22,12 +20,4 @@ class test_xmlrpc(openerp.tests.common.HttpCase):
ids = o.execute(DB, 1, 'admin', 'ir.model', 'search', [], {})
self.assertIsInstance(ids, list)
- # This test was written to test the creation of a new RPC endpoint, not
- # really for the EDI itself.
- #def test_xmlrpc_import_edi_document(self):
- # """ Try to call an EDI method. """
- # msg_re = 'EDI Document is empty!'
- # with self.assertRaisesRegexp(Exception, msg_re):
- # self.proxy.edi_60.import_edi_document(DB, ADMIN_USER_ID, ADMIN_PASSWORD, {})
-
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/tests/common.py b/openerp/tests/common.py
index d2db62c21a0..b3f6dbe81a3 100644
--- a/openerp/tests/common.py
+++ b/openerp/tests/common.py
@@ -17,8 +17,6 @@ import unittest2
import urllib2
import xmlrpclib
from datetime import datetime, timedelta
-from shutil import rmtree
-from tempfile import mkdtemp
import werkzeug
@@ -47,7 +45,8 @@ def at_install(flag):
whether the test should (``True``) or should not (``False``) run during
module installation.
- By default, tests are run at install.
+ By default, tests are run right after installing the module, before
+ starting the installation of the next module.
"""
def decorator(obj):
obj.at_install = flag
@@ -59,7 +58,8 @@ def post_install(flag):
specifying whether the test should or should not run after a set of
module installations.
- By default, tests are *not* run after installation.
+ By default, tests are *not* run after installation of all modules in the
+ current installation set.
"""
def decorator(obj):
obj.post_install = flag
@@ -78,10 +78,13 @@ class BaseCase(unittest2.TestCase):
return self.registry.cursor()
def ref(self, xid):
- """ Returns database ID corresponding to a given identifier.
+ """ Returns database ID for the provided :term:`external identifier`,
+ shortcut for ``get_object_reference``
- :param xid: fully-qualified record identifier, in the form ``module.identifier``
- :raise: ValueError if not found
+ :param xid: fully-qualified :term:`external identifier`, in the form
+ :samp:`{module}.{identifier}`
+ :raise: ValueError if not found
+ :returns: registered id
"""
assert "." in xid, "this method requires a fully qualified parameter, in the following form: 'module.identifier'"
module, xid = xid.split('.')
@@ -89,10 +92,13 @@ class BaseCase(unittest2.TestCase):
return id
def browse_ref(self, xid):
- """ Returns a browsable record for the given identifier.
+ """ Returns a record object for the provided
+ :term:`external identifier`
- :param xid: fully-qualified record identifier, in the form ``module.identifier``
- :raise: ValueError if not found
+ :param xid: fully-qualified :term:`external identifier`, in the form
+ :samp:`{module}.{identifier}`
+ :raise: ValueError if not found
+ :returns: :class:`~openerp.models.BaseModel`
"""
assert "." in xid, "this method requires a fully qualified parameter, in the following form: 'module.identifier'"
module, xid = xid.split('.')
@@ -100,15 +106,17 @@ class BaseCase(unittest2.TestCase):
class TransactionCase(BaseCase):
- """
- Subclass of BaseCase with a single transaction, rolled-back at the end of
- each test (method).
+ """ TestCase in which each test method is run in its own transaction,
+ and with its own cursor. The transaction is rolled back and the cursor
+ is closed after each test.
"""
def setUp(self):
self.registry = RegistryManager.get(DB)
+ #: current transaction's cursor
self.cr = self.cursor()
self.uid = openerp.SUPERUSER_ID
+ #: :class:`~openerp.api.Environment` for the current test case
self.env = api.Environment(self.cr, self.uid, {})
def tearDown(self):
@@ -117,9 +125,9 @@ class TransactionCase(BaseCase):
class SingleTransactionCase(BaseCase):
- """
- Subclass of BaseCase with a single transaction for the whole class,
- rolled-back after all the tests.
+ """ TestCase in which all test methods are run in the same transaction,
+ the transaction is started with the first test method and rolled back at
+ the end of the last.
"""
@classmethod
@@ -155,7 +163,7 @@ class RedirectHandler(urllib2.HTTPRedirectHandler):
https_response = http_response
class HttpCase(TransactionCase):
- """ Transactionnal HTTP TestCase with url_open and phantomjs helpers.
+ """ Transactional HTTP TestCase with url_open and phantomjs helpers.
"""
def __init__(self, methodName='runTest'):