diff --git a/doc/reference/images/tests.png b/doc/reference/images/tests.png index 1e806a6d4a8..11552c0539d 100644 Binary files a/doc/reference/images/tests.png and b/doc/reference/images/tests.png differ diff --git a/doc/reference/testing.rst b/doc/reference/testing.rst index d14b3c25838..9196fd876c9 100644 --- a/doc/reference/testing.rst +++ b/doc/reference/testing.rst @@ -10,9 +10,9 @@ 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 unit tests (see `Testing Python code`_): useful for testing model business logic +- JS unit tests (see `Testing JS code`_): useful to test the javascript code in isolation +- Tours (see `Integration Testing`_): tours simulate a real situation. They ensures that the python and the javascript parts properly talk to each other. Testing Python code @@ -257,35 +257,242 @@ Run only the tests from stock or tagged as slow: Testing JS code =============== +Testing a complex system is an important safeguard to prevent regressions and to +guarantee that some basic functionality still works. Since Odoo has a non trivial +codebase in Javascript, it is necessary to test it. In this section, we will +discuss the practice of testing JS code in isolation: these tests stay in the +browser, and are not supposed to reach the server. + 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. +The Odoo framework uses the QUnit_ library testing framework as a test runner. +QUnit defines the concepts of *tests* and *modules* (a set of related tests), +and gives us a web based interface to execute the tests. -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). +For example, here is what a pyUtils test could look like: -.. image:: ./images/runner.png - :align: center +.. code-block:: javascript -Clicking any runner button will launch the corresponding tests in the -bundled QUnit_ runner: + QUnit.module('py_utils'); + + QUnit.test('simple arithmetic', function (assert) { + assert.expect(2); + + var result = pyUtils.py_eval("1 + 2"); + assert.strictEqual(result, 3, "should properly evaluate sum"); + result = pyUtils.py_eval("42 % 5"); + assert.strictEqual(result, 2, "should properly evaluate modulo operator"); + }); + +The main way to run the test suite is to have a running Odoo server, then +navigate a web browser to ``/web/tests``. The test suite will then be executed +by the web browser Javascript engine. .. image:: ./images/tests.png :align: center -Writing a test case -------------------- +The web UI has many useful features: it can run only some submodules, or +filter tests that match a string. It can show every assertions, failed or passed, +rerun specific tests, ... -This section will be updated as soon as possible. -.. _qunit: http://qunitjs.com/ +Testing Infrastructure +---------------------- + +Here is a high level overview of the most important parts of the testing +infrastructure: + +- there is an asset bundle named `web.js_tests_assets`_. This bundle contains + the main code (assets common + assets backend), some libraries, the QUnit test + runner, and some additional helper code + +- another asset bundle, `web.qunit_suite`_, contains all the tests (and the + js_tests_assets code). Almost all the test files should be added to this + bundle + +- there is a `controller`_ in web, mapped to the route */web/tests*. This controller + simply renders the *web.qunit_suite* template. + +- to execute the tests, one can simply point its browser to the route */web/tests*. + In that case, the browser will download all assets, and QUnit will take over. + +- there is some code in `qunit_config.js`_ which logs in the console some + information when a test passes or fails. + +- we want the runbot to also run these tests, so there is a test (in `test_js.py`_) + which simply spawns a browser and points it to the *web/tests* url. Note that + the phantom_js method does not spawn phantom_js, but Chrome headless instead. + + +Modularity and testing +---------------------- + +With the way Odoo is designed, any addon can modify the behaviour of other parts +of the system. For example, the *voip* addon can modify the *FieldPhone* widget +to use extra features. This is not really good from the perspective of the +testing system, since this means that a test in the addon web will fail whenever +the voip addon is installed (note that the runbot runs the tests with all addons +installed). + +At the same time, our testing sytem is good, because it can detect whenever +another module breaks some core functionality. There is no complete solution to +this issue. For now, we solve this on a case by case basis. + +Usually, it is not a good idea to modify some other behaviour. For our voip +example, it is certainly cleaner to add a new *FieldVOIPPhone* widget and +modify the few views that needs it. This way, the *FieldPhone* widget is not +impacted, and both can be tested. + +Adding a new test case +---------------------- + +Let us assume that we are maintaining an addon *my_addon*, and that we +want to add a test for some javascript code (for example, some utility function +myFunction, located in *my_addon.utils*). The process to add a new test case is +the following: + +1. create a new file *my_addon/static/tests/utils_tests.js*. This file contains the basic code to + add a QUnit module *my_addon > utils*. + + .. code-block:: javascript + + odoo.define('my_addon.utils_tests', function (require) { + "use strict"; + + var utils = require('my_addon.utils'); + + QUnit.module('my_addon', {}, function () { + + QUnit.module('utils'); + + }); + }); + + +2. In *my_addon/assets.xml*, add the file to the main test assets: + + .. code-block:: xml + + + +