~openerp-community/openobject-doc/ksa-openobject-doc-6.0

« back to all changes in this revision

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

  • Committer: Don Kirkby
  • Date: 2011-02-21 20:46:11 UTC
  • mfrom: (433.1.53 openobject-doc)
  • Revision ID: donkirkby+launpd@gmail.com-20110221204611-1ykt6dmg4k3gh5dh
[MERGE] revisions 477 to 486 from the 5.0 branch.

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 you to
 
12
..
 
13
 
 
14
Since version 4.2 of OpenERP, the XML api provides several features to test your modules. They allow you 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 OpenERP'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 OpenERP'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 you 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 you 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 you 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 won't be automatically transmitted to them, however it applies on <value>) 
 
57
..
 
58
 
 
59
        allows you 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 won't 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 as 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 as 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 credits must be equal to the sum of the debits for all non draft entries in the accounting module. Putting tests in update sections is very useful 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 credits must be equal to the sum of the debits for all non draft entries in the accounting module. Putting tests in update sections is very useful 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 you to define some assertions that have to be checked at boot time. Example :
 
111
..
 
112
 
 
113
The assert tag allows you to define some assertions 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 Open sprl">
 
118
.. i18n:            <test expr="name">Open 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 Open sprl">
 
125
            <test expr="name">Open 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. The default is error. If an assertion of too high severity fails, an exception is thrown and the parsing stops. If that happens 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 through the ``--assert-exit-level`` argument.
 
156
..
 
157
 
 
158
The severity attribute defines the level of the assertion: debug, info, warning, error or critical. The default is error. If an assertion of too high severity fails, an exception is thrown and the parsing stops. If that happens 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 through the ``--assert-exit-level`` argument.
 
159
 
 
160
.. i18n: As sometimes you do not know the id when you're writing the test, you can use a search instead. So we can define another example, which will be always true:
 
161
..
 
162
 
 
163
As sometimes you do not know the id when you're writing the test, you can use a search instead. 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 won't 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 won't 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" 
 
192
.. i18n:                 count="1">
 
193
.. i18n:            <test expr="name">Agrolait</test>
 
194
.. i18n:        </assert>
 
195
..
 
196
 
 
197
.. code-block:: xml
 
198
        
 
199
        <assert model="res.partner" 
 
200
                search="[('name','=','Agrolait')]" 
 
201
                string="The name of Agrolait is :Agrolait" 
 
202
                count="1">
 
203
            <test expr="name">Agrolait</test>
 
204
        </assert>
 
205
 
 
206
.. i18n: :Example:
 
207
..
 
208
 
 
209
:Example:
 
210
 
 
211
.. i18n: Require the version of a module.
 
212
..
 
213
 
 
214
Require the version of a module.
 
215
 
 
216
.. i18n: .. code-block:: xml
 
217
.. i18n:        
 
218
.. i18n:        <!-- modules requirement -->
 
219
.. i18n:        <assert model="ir.module.module" 
 
220
.. i18n:                 search="[('name','=','common')]" 
 
221
.. i18n:                 severity="critical" count="1">
 
222
.. i18n:            <test expr="state == 'installed'" />
 
223
.. i18n:            <!-- only check module version -->
 
224
.. i18n:            <test expr="'.'.join(installed_version.split('.')[3:]) >= '2.4'" />
 
225
.. i18n:        </assert>
 
226
.. i18n:        
 
227
.. i18n:        
 
228
.. i18n: Workflow Tag
 
229
.. i18n: =============
 
230
..
 
231
 
 
232
.. code-block:: xml
 
233
        
 
234
        <!-- modules requirement -->
 
235
        <assert model="ir.module.module" 
 
236
                search="[('name','=','common')]" 
 
237
                severity="critical" count="1">
 
238
            <test expr="state == 'installed'" />
 
239
            <!-- only check module version -->
 
240
            <test expr="'.'.join(installed_version.split('.')[3:]) >= '2.4'" />
 
241
        </assert>
 
242
        
 
243
        
 
244
Workflow Tag
 
245
=============
 
246
 
 
247
.. 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:
 
248
..
 
249
 
 
250
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:
 
251
 
 
252
.. i18n: .. code-block:: xml
 
253
.. i18n:        
 
254
.. i18n:        <workflow model="sale.order" ref="test_order_1" action="order_confirm" />
 
255
..
 
256
 
 
257
.. code-block:: xml
 
258
        
 
259
        <workflow model="sale.order" ref="test_order_1" action="order_confirm" />
 
260
 
 
261
.. i18n: This is the syntax to send the signal ``order_confirm`` to the sale order with id ``test_order_1``.
 
262
..
 
263
 
 
264
This is the syntax to send the signal ``order_confirm`` to the sale order with id ``test_order_1``.
 
265
 
 
266
.. 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:
 
267
..
 
268
 
 
269
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:
 
270
 
 
271
.. i18n: .. code-block:: xml
 
272
.. i18n:        
 
273
.. i18n:        <workflow model="sale.order" ref="test_order_1" action="manual_invoice" uid="base.user_admin" />
 
274
..
 
275
 
 
276
.. code-block:: xml
 
277
        
 
278
        <workflow model="sale.order" ref="test_order_1" action="manual_invoice" uid="base.user_admin" />
 
279
 
 
280
.. 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)
 
281
..
 
282
 
 
283
(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)
 
284
 
 
285
.. i18n: In some particular cases, when you write the test, you don't know the id of the object to manipulate through the workflow. It is thus allowed to replace the ref attribute with a value child tag:
 
286
..
 
287
 
 
288
In some particular cases, when you write the test, you don't know the id of the object to manipulate through the workflow. It is thus allowed to replace the ref attribute with a value child tag:
 
289
 
 
290
.. i18n: .. code-block:: xml
 
291
.. i18n:        
 
292
.. i18n:        <workflow model="account.invoice" action="invoice_open">
 
293
.. i18n:            <value model="sale.order" eval="obj(ref('test_order_1')).invoice_ids[0].id" />
 
294
.. i18n:        </workflow>
 
295
..
 
296
 
 
297
.. code-block:: xml
 
298
        
 
299
        <workflow model="account.invoice" action="invoice_open">
 
300
            <value model="sale.order" eval="obj(ref('test_order_1')).invoice_ids[0].id" />
 
301
        </workflow>
 
302
 
 
303
.. i18n: (notice that the eval part must evaluate to a valid database id) 
 
304
..
 
305
 
 
306
(notice that the eval part must evaluate to a valid database id) 
 
307
 
 
308
.. i18n: Function Tag
 
309
.. i18n: ============
 
310
..
 
311
 
 
312
Function Tag
 
313
============
 
314
 
 
315
.. i18n: The function tag allows to call some method of an object. The called method must have the following signature:
 
316
..
 
317
 
 
318
The function tag allows to call some method of an object. The called method must have the following signature:
 
319
 
 
320
.. i18n: def mymethod(self, cr, uid [, …])
 
321
..
 
322
 
 
323
def mymethod(self, cr, uid [, …])
 
324
 
 
325
.. i18n: Where
 
326
..
 
327
 
 
328
Where
 
329
 
 
330
.. i18n:     * cr is the database cursor
 
331
.. i18n:     * uid is the user id 
 
332
..
 
333
 
 
334
    * cr is the database cursor
 
335
    * uid is the user id 
 
336
 
 
337
.. 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.
 
338
..
 
339
 
 
340
Most of the methods defined in Tiny respect that signature as cr and uid are required for a lot of operations, including database access.
 
341
 
 
342
.. i18n: The function tag can then be used to call that method:
 
343
..
 
344
 
 
345
The function tag can then be used to call that method:
 
346
 
 
347
.. i18n: .. code-block:: xml
 
348
.. i18n:        
 
349
.. i18n:        <function model="mypackage.myclass" name="mymethod" />
 
350
..
 
351
 
 
352
.. code-block:: xml
 
353
        
 
354
        <function model="mypackage.myclass" name="mymethod" />
 
355
 
 
356
.. i18n: Most of the time you will want to call your method with additional arguments. Suppose the method has the following signature:
 
357
..
 
358
 
 
359
Most of the time you will want to call your method with additional arguments. Suppose the method has the following signature:
 
360
 
 
361
.. i18n: def mymethod(self, cr, uid, mynumber)
 
362
..
 
363
 
 
364
def mymethod(self, cr, uid, mynumber)
 
365
 
 
366
.. i18n: There are two ways to call that method:
 
367
..
 
368
 
 
369
There are two ways to call that method:
 
370
 
 
371
.. i18n:     * either by using the eval attribute, which must be a python expression evaluating to the list of additional arguments: 
 
372
..
 
373
 
 
374
    * either by using the eval attribute, which must be a python expression evaluating to the list of additional arguments: 
 
375
 
 
376
.. i18n: .. code-block:: xml
 
377
.. i18n:        
 
378
.. i18n:        <function model="mypackage.myclass" name="mymethod" eval="[42]" />
 
379
..
 
380
 
 
381
.. code-block:: xml
 
382
        
 
383
        <function model="mypackage.myclass" name="mymethod" eval="[42]" />
 
384
 
 
385
.. i18n: In that case you have access to all native python functions, to a function ``ref()`` that takes as its argument an XML id and returns the corresponding database id, and to a function ``obj()`` that takes a database id and returns an object with all fields loaded as well as related records.
 
386
..
 
387
 
 
388
In that case you have access to all native python functions, to a function ``ref()`` that takes as its argument an XML id and returns the corresponding database id, and to a function ``obj()`` that takes a database id and returns an object with all fields loaded as well as related records.
 
389
 
 
390
.. i18n:     * or by putting a child node inside the function tag: 
 
391
..
 
392
 
 
393
    * or by putting a child node inside the function tag: 
 
394
 
 
395
.. i18n: .. code-block:: xml
 
396
.. i18n:        
 
397
.. i18n:        <function model="mypackage.myclass" name="mymethod">
 
398
.. i18n:             <value eval="42" />
 
399
.. i18n:        </function>
 
400
..
 
401
 
 
402
.. code-block:: xml
 
403
        
 
404
        <function model="mypackage.myclass" name="mymethod">
 
405
             <value eval="42" />
 
406
        </function>
 
407
 
 
408
.. i18n: Only value and function tags have 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 the attribute will be evaluated first and child nodes will be appended to the resulting list. 
 
409
..
 
410
 
 
411
Only value and function tags have 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 the attribute will be evaluated first and child nodes will be appended to the resulting list. 
 
412
 
 
413
.. i18n: ==================
 
414
.. i18n: Acceptance testing
 
415
.. i18n: ==================
 
416
..
 
417
 
 
418
==================
 
419
Acceptance testing
 
420
==================
 
421
 
 
422
.. i18n: This document describes all tests that are made each time someone install OpenERP 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 OpenERP.
 
423
..
 
424
 
 
425
This document describes all tests that are made each time someone install OpenERP 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 OpenERP.
 
426
 
 
427
.. i18n: Integrity tests on migrations
 
428
.. i18n: =============================
 
429
..
 
430
 
 
431
Integrity tests on migrations
 
432
=============================
 
433
 
 
434
.. i18n:             * Sum credit = Sum debit
 
435
.. i18n:             * Balanced account chart 
 
436
..
 
437
 
 
438
            * Sum credit = Sum debit
 
439
            * Balanced account chart 
 
440
 
 
441
.. i18n: ... Describe all integrity tests here
 
442
..
 
443
 
 
444
... Describe all integrity tests here
 
445
 
 
446
.. i18n: Workflow tests
 
447
.. i18n: ==============
 
448
..
 
449
 
 
450
Workflow tests
 
451
==============
 
452
 
 
453
.. i18n: ... Describe all processes tested here.
 
454
..
 
455
 
 
456
... Describe all processes tested here.
 
457
 
 
458
.. i18n: Record creation
 
459
.. i18n: ===============
 
460
..
 
461
 
 
462
Record creation
 
463
===============
 
464
 
 
465
.. i18n: More than 300 records are created, describe them here. 
 
466
..
 
467
 
 
468
More than 300 records are created, describe them here.