测试

单元测试

自OpenERP 4.2版以来, 新增了利用XML文件进行模块测试的功能. 可以完成:

  • 测试记录属性,类常量等。
  • 测试您的方法
  • 操作对象,以检查流程和特殊方法

可以利用这些来模拟一个用户与系统的交互来测试你的模块.

概述

单元测试主要通过 OpenERP XML 文件的三个标签 : <assert>, <workflow> 和 <function> 来完成。其共有属性如下:

uid:
可指定 User ID 来完成交互 (你必须指定该用户的 XML id, 如 “base.user_demo”)
context:
可指定上下文字典(Python 表达式)内容(对于 <function> 标签需注意不是所有对象方法都会读取 context ,因此上下文不一定会传递。但对 <value> 标签可用)

这2个属性可设置在任意标签(对于 <functions> 标签,只有根 root <functions> 标签可用)中,或 <data> 标签本身。如果你同时设置,context 会自动合并。

注意:单元测试标签在<data> 里设置为 noupdate 时,将不会被解析。

使用单元测试

你可以在XML文件中声名单元测试,我们建议你如下面的样子命名:

  • module_name_test.xml

如果你的测试在 __openerp__.py 作为演示数据申明,那么将会在系统安装演示数据时检查。例如,在生成发票过程中,测试销售订单是否产生了正确的金额。

如果你的测试申明为初始数据(init),那么将在模块安装时检查。可以在模块安装后检查数据的一致性。

如果你的测试数据在升级部分申明,那么将在模块安装和升级时检查。用于检查数据一致性和常量。例如,会计模块中,所有非草稿状态分录总和贷方必须等于借方。将测试放在升级章节中,在模块迁移和升级中是非常有用的。

断言标签

断言标签允许你定义某些断言,这些断言将会启动的时候检查。如:

<assert model="res.company" id="main_company" string="The main company name is Open sprl">
    <test expr="name">Open sprl</test>
</assert>

该断言将会检查 id 为 main_company 的 company 对象名字是否匹配 “Open sprl” 。expr 字段指定一个 python 表达式计算。该表达式可以读取指定对象的任意字段或是 python 内置函数(如sum, reduce等)。ref 函数指定数据库ID 对应的 XML id,同样也是可用(在某些例子中,ref 同时也是指定对象的属性名,这时应该使用 _ref 来代替)。经过计算后的结果值将会与 test 标签文本值比较。假如断言失败,相关属性值和测试标签信息将会作为一条消息记录下来。

在更复杂的测试中,也可以使用计算结果为 True 的 python 表达式。

<assert model="res.company"
        id="main_company"
        string="The main company's currency is €" severity="warning">
    <test expr="currency_id.code == 'eur'.upper()"/>
</assert>

severity 标签定义了断言的级别:debug, info, warning, error 或 critical,默认值为 error 。如果断言严重失败,那么将抛出一个异常,然后停止解析。如果是发生在服务初始化阶段,你们程序将中止。除此之外,其它的所有异常将会发送到客户端。默认情况下,系统将会在 warning 级别抛出失败异常,但可以通过 –assert-exit-leve 启动参数设置。

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:

<assert model="res.partner"
        search="[('name','=','Agrolait')]"
        string="The name of Agrolait is :Agrolait">
    <test expr="name">Agrolait</test>
</assert>

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:

<assert model="res.partner"
        search="[('name','=','Agrolait')]"
        string="The name of Agrolait is :Agrolait"
        count="1">
    <test expr="name">Agrolait</test>
</assert>
Example:

Require the version of a module.

<!-- modules requirement -->
<assert model="ir.module.module"
        search="[('name','=','common')]"
        severity="critical" count="1">
    <test expr="state == 'installed'" />
    <!-- only check module version -->
    <test expr="'.'.join(installed_version.split('.')[3:]) >= '2.4'" />
</assert>

工作流标签

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:

<workflow model="sale.order" ref="test_order_1" action="order_confirm" />

This is the syntax to send the signal order_confirm to the sale order with id test_order_1.

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:

<workflow model="sale.order" ref="test_order_1" action="manual_invoice" uid="base.user_admin" />

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

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:

<workflow model="account.invoice" action="invoice_open">
    <value model="sale.order" eval="obj(ref('test_order_1')).invoice_ids[0].id" />
</workflow>

(notice that the eval part must evaluate to a valid database id)

函数标签

The function tag allows to call some method of an object. The called method must have the following signature:

def mymethod(self, cr, uid [, …])

Where

  • cr is the database cursor
  • uid is the user id

Most of the methods defined in Tiny respect that signature as cr and uid are required for a lot of operations, including database access.

The function tag can then be used to call that method:

<function model="mypackage.myclass" name="mymethod" />

Most of the time you will want to call your method with additional arguments. Suppose the method has the following signature:

def mymethod(self, cr, uid, mynumber)

There are two ways to call that method:

  • either by using the eval attribute, which must be a python expression evaluating to the list of additional arguments:
<function model="mypackage.myclass" name="mymethod" eval="[42]" />

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.

  • or by putting a child node inside the function tag:
<function model="mypackage.myclass" name="mymethod">
     <value eval="42" />
</function>

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.

验收测试

这个文档描述的是所有人在计算机上安装OpenERP的测试。你可以假设所有测试都已通过致使我们必须更新整合到发行版的新模块中或者一个新OpenERP候选版本中。

迁移完整性测试

  • Sum credit = Sum debit
  • Balanced account chart

... Describe all integrity tests here

工作流测试

... Describe all processes tested here.

记录生成

More than 300 records are created, describe them here.