Odoo supports different ways of writing addon module tests, YAML tests, and Python tests. In this recipe, we will see how to write YAML tests for the my_module
methods we wrote in Chapter 5, Basic Server Side Development, in the recipe Define Model methods and use the API decorators.
This recipe assumes you have an instance ready with the code for the my_module
module defined in Chapter 3, Creating Odoo Modules, and the code from the Define Model methods and use the API decorators recipe in Chapter 5, Basic Server
Side Development.
In order to write YAML unit tests for my_module
, you need to follow these steps:
__openerp__.py
file of the module, and add the test's entry:{ # … 'test': ['test/test_books.yml'] }
test
directory in my_module
:$ mkdir test
test_books.yml
in the directory. Add a test description at the top:- Test LibraryBook.change_state
- !context uid: 'base.user_demo'
- create book in draft state - !record {model: library.book, id: testbook}: - name: Test Book - state: draft
change_state
method:- call change_state to make book available - !python {model: library.book, id: testbook}: | self.change_state('available')
- !assert {model: library.book, id: testbook, string: wrong state}: - state == 'available'
change_state
method with a forbidden state:- try to call change_state to make book draft - !python {model: library.book, id: testbook}: | self.change_state('draft') - check the book is still available - !assert {model: library.book, id: testbook, string: wrong state}: - state == 'available'
The YAML files we are using here are the same as the ones used to load data files (see Chapter 9, Module Data), except that they are included in the test key of the __openerp__.py
rather than in the data key. We add that key in step 1. They are therefore processed only when running the tests (see the Running Server Tests recipe in this chapter).
Step 3 adds a description at the top of the test file in a YAML test node. Mind the indentation of the text, after the - delimiting a node. This description will be printed in the test log (at log level DEBUG
).
Step 4 uses a !context
YAML node to change the evaluation context used in the test. The most common use of this node is to modify the user used to run the test from the administrator to someone else by assigning a string containing the XML ID of the user to uid
.
Step 5 creates some test data using a !record
YAML node. The YAML attributes, between braces, give the name of the model to be used and the XML ID to use for the new record.
Step 6 uses a !python
YAML node to execute some Python code. The attributes specify the model to be used and the XML ID of the record. Inside the block, self
is a recordset of the specified model containing a single record with the supplied XML ID.
Inside the Python block, you may also use the following variables:
ref
: This is a function returning a recordset from an XML ID passed as a stringtime
: This is the time
module from the Python standard librarydatetime
: This is the datetime
type from the datetime
module of the Python standard librarytimedelta
: This is the timedelta
type from the datetime
module of the Python standard libraryIn step 7, we use an !assert
YAML node to make assertions about the record. The attributes specify the model to use and on which XML ID the assertions must be checked. The string attribute is used in the error message if one of the checks in the node is not True
.
See the following recipe, Run server tests, to see how to run the test.
When !assert
is not convenient for writing checks, for instance, if you don't have an XML ID for the record you want to check, you can use a !python
block and the assert
Python keyword. We could also rewrite the last check of the recipe like this:
-
try to call change_state to make book draft, check this has no effect
-
!python {model: library.book, id: testbook}: |
self.change_state('draft')
assert self.state == 'available', 'wrong state %s' % self.state