~openerp-dev/openobject-doc/trunk

« back to all changes in this revision

Viewing changes to i18n/it/source/developer/5_20_unit_testing/index.rst

  • Committer: Antony Lesuisse
  • Date: 2010-03-05 16:46:40 UTC
  • Revision ID: al@openerp.com-20100305164640-9b7anc1t5ujha8lw
Merge doc into feature, before deletion of both features and doc. (odo)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
.. i18n: ============
 
3
.. i18n: Unit testing
 
4
.. i18n: ============
 
5
..
 
6
 
 
7
============
 
8
Unit testing
 
9
============
 
10
 
 
11
.. i18n: Since version 4.2 of OpenERP, the XML api provides several features to test your modules. They allow to
 
12
..
 
13
 
 
14
Since version 4.2 of OpenERP, the XML api provides several features to test your modules. They allow to
 
15
 
 
16
.. i18n:     * test the properties of your records, your class invariants etc.
 
17
.. i18n:     * test your methods
 
18
.. i18n:     * manipulate your objects to check your workflows and specific methods 
 
19
..
 
20
 
 
21
    * test the properties of your records, your class invariants etc.
 
22
    * test your methods
 
23
    * manipulate your objects to check your workflows and specific methods 
 
24
 
 
25
.. i18n: This thus allows you to simulate user interaction and automatically test your modules.
 
26
..
 
27
 
 
28
This thus allows you to simulate user interaction and automatically test your modules.
 
29
 
 
30
.. i18n: Generalities
 
31
.. i18n: ============
 
32
.. i18n:  
 
33
.. i18n: As you will see in the next pages, unit testing through Open ERP's XML can be done using three main tags: <assert>, <workflow> and <function>. All these tags share some common optional attributes:
 
34
..
 
35
 
 
36
Generalities
 
37
============
 
38
 
 
39
As you will see in the next pages, unit testing through Open ERP's XML can be done using three main tags: <assert>, <workflow> and <function>. All these tags share some common optional attributes:
 
40
 
 
41
.. i18n: :uid:
 
42
..
 
43
 
 
44
:uid:
 
45
 
 
46
.. i18n:        allows to do the tag interpretation through a specific User ID (you must specify the XML id of that user, for example "base.user_demo") 
 
47
..
 
48
 
 
49
        allows to do the tag interpretation through a specific User ID (you must specify the XML id of that user, for example "base.user_demo") 
 
50
 
 
51
.. i18n: :context:
 
52
..
 
53
 
 
54
:context:
 
55
 
 
56
.. i18n:        allows to specify a context dictionary (given as a Python expression) to use when applicable (for <function> notice that not all objects methods take a context attribute so it wont be automatically transmitted to them, however it applies on <value>) 
 
57
..
 
58
 
 
59
        allows to specify a context dictionary (given as a Python expression) to use when applicable (for <function> notice that not all objects methods take a context attribute so it wont be automatically transmitted to them, however it applies on <value>) 
 
60
 
 
61
.. i18n: These two attributes might be set on any of those tags (for <functions>, only the root <function> tag may accept it) or on the <data> tag itself. If you set a context attribute on both, they will be merged automatically.
 
62
..
 
63
 
 
64
These two attributes might be set on any of those tags (for <functions>, only the root <function> tag may accept it) or on the <data> tag itself. If you set a context attribute on both, they will be merged automatically.
 
65
 
 
66
.. i18n: Notice that Unit Testing tags will not be interpreted inside a <data> tag set in noupdate.
 
67
..
 
68
 
 
69
Notice that Unit Testing tags will not be interpreted inside a <data> tag set in noupdate.
 
70
 
 
71
.. i18n: Using unit tests
 
72
.. i18n: ================
 
73
..
 
74
 
 
75
Using unit tests
 
76
================
 
77
 
 
78
.. i18n: You can declare unit tests in all your .XML files. We suggest you to name the files like this:
 
79
..
 
80
 
 
81
You can declare unit tests in all your .XML files. We suggest you to name the files like this:
 
82
 
 
83
.. i18n:     * module_name_test.xml 
 
84
..
 
85
 
 
86
    * module_name_test.xml 
 
87
 
 
88
.. i18n: If your tests are declared at demo data in the __terp__.py, they will be checked at the installation of the system with demo data. Example of usage, testing the the demo sale order produce a correct amount in the generated invoice.
 
89
..
 
90
 
 
91
If your tests are declared at demo data in the __terp__.py, they will be checked at the installation of the system with demo data. Example of usage, testing the the demo sale order produce a correct amount in the generated invoice.
 
92
 
 
93
.. i18n: If your tests are declared like init data, they will be checked at all installation of the softwares. Use it to test the consistency of the software after installation.
 
94
..
 
95
 
 
96
If your tests are declared like init data, they will be checked at all installation of the softwares. Use it to test the consistency of the software after installation.
 
97
 
 
98
.. i18n: If your tests are declared in update sections, the tests are checked at the installation and also at all updates. Use it to tests consistencies, invariants of the module. Example: The sum of the credit must be equals to the sum of the debit for all non draft entries in the accounting module. Putting tests in update sections is very usefull to check consistencies of migrations or new version upgrades. 
 
99
..
 
100
 
 
101
If your tests are declared in update sections, the tests are checked at the installation and also at all updates. Use it to tests consistencies, invariants of the module. Example: The sum of the credit must be equals to the sum of the debit for all non draft entries in the accounting module. Putting tests in update sections is very usefull to check consistencies of migrations or new version upgrades. 
 
102
 
 
103
.. i18n: Assert Tag
 
104
.. i18n: ==========
 
105
..
 
106
 
 
107
Assert Tag
 
108
==========
 
109
 
 
110
.. i18n: The assert tag allows to define some assertion that have to be checked at boot time. Example :
 
111
..
 
112
 
 
113
The assert tag allows to define some assertion that have to be checked at boot time. Example :
 
114
 
 
115
.. i18n: .. code-block:: xml
 
116
.. i18n:        
 
117
.. i18n:        <assert model="res.company" id="main_company" string="The main company name is Tiny SPRL">
 
118
.. i18n:            <test expr="name">Tiny sprl</test>
 
119
.. i18n:        </assert>
 
120
..
 
121
 
 
122
.. code-block:: xml
 
123
        
 
124
        <assert model="res.company" id="main_company" string="The main company name is Tiny SPRL">
 
125
            <test expr="name">Tiny sprl</test>
 
126
        </assert>
 
127
 
 
128
.. i18n: This assert will check that the company with id main_company has a name equal to "Open sprl". The expr field specifies a python expression to evaluate. The expression can access any field of the specified model and any python built-in function (such as sum, reduce etc.). The ref function, which gives the database id corresponding to a specified XML id, is also available (in the case that "ref" is also the name of an attribute of the specified model, you can use _ref instead). The resulting value is then compared with the text contained in the test tag. If the assertion fails, it is logged as a message containing the value of the string attribute and the test tag that failed.
 
129
..
 
130
 
 
131
This assert will check that the company with id main_company has a name equal to "Open sprl". The expr field specifies a python expression to evaluate. The expression can access any field of the specified model and any python built-in function (such as sum, reduce etc.). The ref function, which gives the database id corresponding to a specified XML id, is also available (in the case that "ref" is also the name of an attribute of the specified model, you can use _ref instead). The resulting value is then compared with the text contained in the test tag. If the assertion fails, it is logged as a message containing the value of the string attribute and the test tag that failed.
 
132
 
 
133
.. i18n: For more complex tests it is not always sufficient to compare a result to a string. To do that you may instead omit the tag's content and just put an expression that must evaluate to True:
 
134
..
 
135
 
 
136
For more complex tests it is not always sufficient to compare a result to a string. To do that you may instead omit the tag's content and just put an expression that must evaluate to True:
 
137
 
 
138
.. i18n: .. code-block:: xml
 
139
.. i18n:        
 
140
.. i18n:        <assert model="res.company" 
 
141
.. i18n:                 id="main_company" 
 
142
.. i18n:                 string="The main company's currency is €" : severity="warning">
 
143
.. i18n:            <test expr="currency_id.code == 'eur'.upper()"/>
 
144
.. i18n:        </assert>
 
145
..
 
146
 
 
147
.. code-block:: xml
 
148
        
 
149
        <assert model="res.company" 
 
150
                id="main_company" 
 
151
                string="The main company's currency is €" : severity="warning">
 
152
            <test expr="currency_id.code == 'eur'.upper()"/>
 
153
        </assert>
 
154
 
 
155
.. i18n: The severity attribute defines the level of the assertion: debug, info, warning, error or critical. If an assertion of too high severity fails, an exception is thrown and the parsing stops. If that appends during server initialization, the server will stop. Else the exception will be transmitted to the client. The level at which a failure will throw an exception is by default at warning, but can be specified at server launch trough the --assert-exit-level argument.
 
156
..
 
157
 
 
158
The severity attribute defines the level of the assertion: debug, info, warning, error or critical. If an assertion of too high severity fails, an exception is thrown and the parsing stops. If that appends during server initialization, the server will stop. Else the exception will be transmitted to the client. The level at which a failure will throw an exception is by default at warning, but can be specified at server launch trough the --assert-exit-level argument.
 
159
 
 
160
.. i18n: As sometimes you do not know the id a priori, that attribute can be substituted by a search. So we can define another example, which will be always true :
 
161
..
 
162
 
 
163
As sometimes you do not know the id a priori, that attribute can be substituted by a search. So we can define another example, which will be always true :
 
164
 
 
165
.. i18n: .. code-block:: xml
 
166
.. i18n:        
 
167
.. i18n:        <assert model="res.partner" 
 
168
.. i18n:                 search="[('name','=','Agrolait')]" 
 
169
.. i18n:                 string="The name of Agrolait is :Agrolait">
 
170
.. i18n:            <test expr="name">Agrolait</test>
 
171
.. i18n:        </assert>
 
172
..
 
173
 
 
174
.. code-block:: xml
 
175
        
 
176
        <assert model="res.partner" 
 
177
                search="[('name','=','Agrolait')]" 
 
178
                string="The name of Agrolait is :Agrolait">
 
179
            <test expr="name">Agrolait</test>
 
180
        </assert>
 
181
 
 
182
.. i18n: When you use the search, each resulting record is tested but the assertion is counted only once. Thus if an assertion fails, the remaining records wont be tested. In addition, if the search finds no record, nothing will be tested so the assertion will be considered successful. If you want to make sure that there are a certain number of results, you might use the count parameter:
 
183
..
 
184
 
 
185
When you use the search, each resulting record is tested but the assertion is counted only once. Thus if an assertion fails, the remaining records wont be tested. In addition, if the search finds no record, nothing will be tested so the assertion will be considered successful. If you want to make sure that there are a certain number of results, you might use the count parameter:
 
186
 
 
187
.. i18n: .. code-block:: xml
 
188
.. i18n:        
 
189
.. i18n:        <assert model="res.partner" 
 
190
.. i18n:                 search="[('name','=','Agrolait')]" 
 
191
.. i18n:                 string="The name of Agrolait is :Agrolait" count="1">
 
192
.. i18n:            <test expr="name">Agrolait</test>
 
193
.. i18n:        </assert>
 
194
..
 
195
 
 
196
.. code-block:: xml
 
197
        
 
198
        <assert model="res.partner" 
 
199
                search="[('name','=','Agrolait')]" 
 
200
                string="The name of Agrolait is :Agrolait" count="1">
 
201
            <test expr="name">Agrolait</test>
 
202
        </assert>
 
203
 
 
204
.. i18n: :Example:
 
205
..
 
206
 
 
207
:Example:
 
208
 
 
209
.. i18n: Require the version of a module.
 
210
..
 
211
 
 
212
Require the version of a module.
 
213
 
 
214
.. i18n: .. code-block:: xml
 
215
.. i18n:        
 
216
.. i18n:        <!-- modules requirement -->
 
217
.. i18n:        <assert model="ir.module.module" 
 
218
.. i18n:                 search="[('name','=','common')]" 
 
219
.. i18n:                 severity="critical" count="1">
 
220
.. i18n:            <test expr="state == 'installed'" />
 
221
.. i18n:            <!-- only check module version -->
 
222
.. i18n:            <test expr="'.'.join(installed_version.split('.')[3:]) >= '2.4'" />
 
223
.. i18n:        </assert>
 
224
.. i18n:        
 
225
.. i18n:        
 
226
.. i18n: Workflow Tag
 
227
.. i18n: =============
 
228
..
 
229
 
 
230
.. code-block:: xml
 
231
        
 
232
        <!-- modules requirement -->
 
233
        <assert model="ir.module.module" 
 
234
                search="[('name','=','common')]" 
 
235
                severity="critical" count="1">
 
236
            <test expr="state == 'installed'" />
 
237
            <!-- only check module version -->
 
238
            <test expr="'.'.join(installed_version.split('.')[3:]) >= '2.4'" />
 
239
        </assert>
 
240
        
 
241
        
 
242
Workflow Tag
 
243
=============
 
244
 
 
245
.. i18n: The workflow tag allows you to call for a transition in a workflow by sending a signal to it. It is generally used to simulate an interaction with a user (clicking on a button…) for test purposes:
 
246
..
 
247
 
 
248
The workflow tag allows you to call for a transition in a workflow by sending a signal to it. It is generally used to simulate an interaction with a user (clicking on a button…) for test purposes:
 
249
 
 
250
.. i18n: .. code-block:: xml
 
251
.. i18n:        
 
252
.. i18n:        <workflow model="sale.order" ref="test_order_1" action="order_confirm" />
 
253
..
 
254
 
 
255
.. code-block:: xml
 
256
        
 
257
        <workflow model="sale.order" ref="test_order_1" action="order_confirm" />
 
258
 
 
259
.. i18n: This is the syntax to send the signal order_confirm to the sale order with id test_order_1.
 
260
..
 
261
 
 
262
This is the syntax to send the signal order_confirm to the sale order with id test_order_1.
 
263
 
 
264
.. i18n: Notice that workflow tags (as all other tags) are interpreted as root which might be a problem if the signals handling needs to use some particular property of the user (typically the user's company, while root does not belong to one). In that case you might specify a user to switch to before handling the signal, through the uid property:
 
265
..
 
266
 
 
267
Notice that workflow tags (as all other tags) are interpreted as root which might be a problem if the signals handling needs to use some particular property of the user (typically the user's company, while root does not belong to one). In that case you might specify a user to switch to before handling the signal, through the uid property:
 
268
 
 
269
.. i18n: .. code-block:: xml
 
270
.. i18n:        
 
271
.. i18n:        <workflow model="sale.order" ref="test_order_1" action="manual_invoice" uid="base.user_admin" />
 
272
..
 
273
 
 
274
.. code-block:: xml
 
275
        
 
276
        <workflow model="sale.order" ref="test_order_1" action="manual_invoice" uid="base.user_admin" />
 
277
 
 
278
.. i18n: (here we had to specify the module base - from which user_admin comes - because this tag is supposed to be placed in an xml file of the sale module)
 
279
..
 
280
 
 
281
(here we had to specify the module base - from which user_admin comes - because this tag is supposed to be placed in an xml file of the sale module)
 
282
 
 
283
.. i18n: In some particular cases, you do not know a priori the id of the object to manipulate through the workflow. It is thus allowed to replace the ref attribute by a value child tag:
 
284
..
 
285
 
 
286
In some particular cases, you do not know a priori the id of the object to manipulate through the workflow. It is thus allowed to replace the ref attribute by a value child tag:
 
287
 
 
288
.. i18n: .. code-block:: xml
 
289
.. i18n:        
 
290
.. i18n:        <workflow model="account.invoice" action="invoice_open">
 
291
.. i18n:            <value model="sale.order" eval="obj(ref('test_order_1')).invoice_ids[0].id" />
 
292
.. i18n:        </workflow>
 
293
..
 
294
 
 
295
.. code-block:: xml
 
296
        
 
297
        <workflow model="account.invoice" action="invoice_open">
 
298
            <value model="sale.order" eval="obj(ref('test_order_1')).invoice_ids[0].id" />
 
299
        </workflow>
 
300
 
 
301
.. i18n: (notice that it the eval part must evaluate to a valid database id) 
 
302
..
 
303
 
 
304
(notice that it the eval part must evaluate to a valid database id) 
 
305
 
 
306
.. i18n: Function Tag
 
307
.. i18n: ============
 
308
..
 
309
 
 
310
Function Tag
 
311
============
 
312
 
 
313
.. i18n: The function tag allows to call some method of an object. The called method must have the following signature:
 
314
..
 
315
 
 
316
The function tag allows to call some method of an object. The called method must have the following signature:
 
317
 
 
318
.. i18n: def mymethod(self, cr, uid [, …])
 
319
..
 
320
 
 
321
def mymethod(self, cr, uid [, …])
 
322
 
 
323
.. i18n: Where
 
324
..
 
325
 
 
326
Where
 
327
 
 
328
.. i18n:     * cr is the database cursor
 
329
.. i18n:     * uid is the user id 
 
330
..
 
331
 
 
332
    * cr is the database cursor
 
333
    * uid is the user id 
 
334
 
 
335
.. i18n: Most of the methods defined in Tiny respect that signature as cr and uid are required for a lot of operations, including database access.
 
336
..
 
337
 
 
338
Most of the methods defined in Tiny respect that signature as cr and uid are required for a lot of operations, including database access.
 
339
 
 
340
.. i18n: The function tag can then be used to call that method:
 
341
..
 
342
 
 
343
The function tag can then be used to call that method:
 
344
 
 
345
.. i18n: .. code-block:: xml
 
346
.. i18n:        
 
347
.. i18n:        <function model="mypackage.myclass" name="mymethod" />
 
348
..
 
349
 
 
350
.. code-block:: xml
 
351
        
 
352
        <function model="mypackage.myclass" name="mymethod" />
 
353
 
 
354
.. i18n: Most of the time you will want to call your method with additional arguments. Suppose the method has the following signature:
 
355
..
 
356
 
 
357
Most of the time you will want to call your method with additional arguments. Suppose the method has the following signature:
 
358
 
 
359
.. i18n: def mymethod(self, cr, uid, mynumber)
 
360
..
 
361
 
 
362
def mymethod(self, cr, uid, mynumber)
 
363
 
 
364
.. i18n: There are two ways to call that method:
 
365
..
 
366
 
 
367
There are two ways to call that method:
 
368
 
 
369
.. i18n:     * either by using the eval attribute, which must be a python expression evaluating to the list of additional arguments: 
 
370
..
 
371
 
 
372
    * either by using the eval attribute, which must be a python expression evaluating to the list of additional arguments: 
 
373
 
 
374
.. i18n: .. code-block:: xml
 
375
.. i18n:        
 
376
.. i18n:        <function model="mypackage.myclass" name="mymethod" eval="[42]" />
 
377
..
 
378
 
 
379
.. code-block:: xml
 
380
        
 
381
        <function model="mypackage.myclass" name="mymethod" eval="[42]" />
 
382
 
 
383
.. i18n: In that case you have access to all native python functions an to a function ref which takes as argument an XML id and returns the corresponding id.
 
384
..
 
385
 
 
386
In that case you have access to all native python functions an to a function ref which takes as argument an XML id and returns the corresponding id.
 
387
 
 
388
.. i18n:     * or by putting a child node inside the function tag: 
 
389
..
 
390
 
 
391
    * or by putting a child node inside the function tag: 
 
392
 
 
393
.. i18n: .. code-block:: xml
 
394
.. i18n:        
 
395
.. i18n:        <function model="mypackage.myclass" name="mymethod">
 
396
.. i18n:             <value eval="42" />
 
397
.. i18n:        </function>
 
398
..
 
399
 
 
400
.. code-block:: xml
 
401
        
 
402
        <function model="mypackage.myclass" name="mymethod">
 
403
             <value eval="42" />
 
404
        </function>
 
405
 
 
406
.. i18n: Only value and function tags have a meaning as function child nodes (using other tags will give unspecified results). This means that you can use the returned result of a method call as an argument of another call. You can put as many child nodes as you want, each one being an argument of the method call (keeping them in order). You can also mix child nodes and the eval attribute. In that case it will be evaluated first and child nodes will be appended to the resulting list. 
 
407
..
 
408
 
 
409
Only value and function tags have a meaning as function child nodes (using other tags will give unspecified results). This means that you can use the returned result of a method call as an argument of another call. You can put as many child nodes as you want, each one being an argument of the method call (keeping them in order). You can also mix child nodes and the eval attribute. In that case it will be evaluated first and child nodes will be appended to the resulting list. 
 
410
 
 
411
.. i18n: ==================
 
412
.. i18n: Acceptance testing
 
413
.. i18n: ==================
 
414
..
 
415
 
 
416
==================
 
417
Acceptance testing
 
418
==================
 
419
 
 
420
.. i18n: This document describes all tests that are made each time someone install Open ERP on a computer. You can then assume that all these tests are valid as we must launch them before publishing a new module or a release of Open ERP.
 
421
..
 
422
 
 
423
This document describes all tests that are made each time someone install Open ERP on a computer. You can then assume that all these tests are valid as we must launch them before publishing a new module or a release of Open ERP.
 
424
 
 
425
.. i18n: Integrity tests on migrations
 
426
.. i18n: =============================
 
427
..
 
428
 
 
429
Integrity tests on migrations
 
430
=============================
 
431
 
 
432
.. i18n:             * Sum credit = Sum debit
 
433
.. i18n:             * Balanced account chart 
 
434
..
 
435
 
 
436
            * Sum credit = Sum debit
 
437
            * Balanced account chart 
 
438
 
 
439
.. i18n: ... Describe all integrity tests here
 
440
..
 
441
 
 
442
... Describe all integrity tests here
 
443
 
 
444
.. i18n: Workflow tests
 
445
.. i18n: ==============
 
446
..
 
447
 
 
448
Workflow tests
 
449
==============
 
450
 
 
451
.. i18n: ... Describe all processus tested here.
 
452
..
 
453
 
 
454
... Describe all processus tested here.
 
455
 
 
456
.. i18n: Record creation
 
457
.. i18n: ===============
 
458
..
 
459
 
 
460
Record creation
 
461
===============
 
462
 
 
463
.. i18n: More than 300 records are created, describe them here. 
 
464
..
 
465
 
 
466
More than 300 records are created, describe them here.