Toggle navigation

Testing Odoo

There are many ways to test an application. In Odoo, we have three kinds of tests

  • python unit tests: useful for testing model business logic
  • js unit tests: this is necessary to test the javascript code in isolation
  • tours: this is a form of integration testing. The tours ensure that the python and the javascript parts properly talk to each other.

Testing Python code

Odoo provides support for testing modules using unittest.

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.

your_module
|-- ...
`-- tests
    |-- __init__.py
    |-- test_bar.py
    `-- test_foo.py

and __init__.py contains:

from . import test_foo, test_bar

Changed in version 8.0: previously, the test runner would only run modules added to two lists fast_suite and checks in tests/__init__.py. In 8.0 it will run all imported modules

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):

class odoo.tests.common.TransactionCase(methodName='runTest')[source]

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.

browse_ref(xid)[source]

Returns a record object for the provided external identifier

Parameters
xid – fully-qualified external identifier, in the form module.identifier
Raise
ValueError if not found
Returns
BaseModel
ref(xid)[source]

Returns database ID for the provided external identifier, shortcut for get_object_reference

Parameters
xid – fully-qualified external identifier, in the form module.identifier
Raise
ValueError if not found
Returns
registered id
class odoo.tests.common.SingleTransactionCase(methodName='runTest')[source]

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.

browse_ref(xid)[source]

Returns a record object for the provided external identifier

Parameters
xid – fully-qualified external identifier, in the form module.identifier
Raise
ValueError if not found
Returns
BaseModel
ref(xid)[source]

Returns database ID for the provided external identifier, shortcut for get_object_reference

Parameters
xid – fully-qualified external identifier, in the form module.identifier
Raise
ValueError if not found
Returns
registered id
class odoo.tests.common.SavepointCase(methodName='runTest')[source]

Similar to SingleTransactionCase in that all test methods are run in a single transaction but each test case is run inside a rollbacked savepoint (sub-transaction).

Useful for test cases containing fast tests but with significant database setup common to all cases (complex in-db test data): setUpClass() can be used to generate db test data once, then all test cases use the same data without influencing one another but without having to recreate the test data either.

class odoo.tests.common.HttpCase(methodName='runTest')[source]

Transactional HTTP TestCase with url_open and phantomjs helpers.

browse_ref(xid)[source]

Returns a record object for the provided external identifier

Parameters
xid – fully-qualified external identifier, in the form module.identifier
Raise
ValueError if not found
Returns
BaseModel
phantom_js(url_path, code, ready='window', login=None, timeout=60, **kw)[source]

Test js code running in the browser - optionnally log as ‘login’ - load page given by url_path - wait for ready object to be available - eval(code) inside the page

To signal success test do: console.log(‘ok’)

To signal failure do: console.log(‘error’)

If neither are done before timeout test fails.

ref(xid)[source]

Returns database ID for the provided external identifier, shortcut for get_object_reference

Parameters
xid – fully-qualified external identifier, in the form module.identifier
Raise
ValueError if not found
Returns
registered id

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:

odoo.tests.common.at_install(flag)[source]

Sets the at-install state of a test, the flag is a boolean specifying whether the test should (True) or should not (False) run during module installation.

By default, tests are run right after installing the module, before starting the installation of the next module.

odoo.tests.common.post_install(flag)[source]

Sets the post-install state of a test. The flag is a boolean specifying whether the test should or should not run after a set of module installations.

By default, tests are not run after installation of all modules in the current installation set.

The most common situation is to use TransactionCase and test a property 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 --test-enable was enabled when starting the Odoo server.

As of Odoo 8, running tests outside of the install/update cycle is not supported.

Testing JS code

Qunit test suite

Odoo Web includes means to unit-test both the core code of Odoo Web and your own javascript modules. On the javascript side, unit-testing is based on QUnit with a number of helpers and extensions for better integration with Odoo.

To see what the runner looks like, find (or start) an Odoo server with the web client enabled, and navigate to /web/tests This will show the runner selector, which lists all modules with javascript unit tests, and allows starting any of them (or all javascript tests in all modules at once).

Clicking any runner button will launch the corresponding tests in the bundled QUnit runner:

Writing a test case

This section will be updated as soon as possible.

Integration Testing

Testing Python code and JS code separately is very useful, but it does not prove that the web client and the server work together. In order to do that, we can write another kind of test: tours. A tour is a mini scenario of some interesting business flow. It explains a sequence of steps that should be followed. The test runner will then create a phantom_js browser, point it to the proper url and simulate the click and inputs, according to the scenario.