测试 Odoo

测试应用程序的方法有很多。在 Odoo 中,我们有三种测试类型:

  • Python 单元测试(参见 Testing Python code ):用于测试模型的业务逻辑

  • JS 单元测试(参见 Testing JS code ):用于单独测试 JavaScript 代码

  • 巡游测试(参见 Integration Testing ):模拟真实场景。它们确保 Python 和 JavaScript 部分能够正确交互。

测试 Python 代码

Odoo 提供了使用 Python 的 unittest 库 测试模块的支持。

要编写测试,只需在模块中定义一个 tests 子包,它将自动被检查以查找测试模块。测试模块的名称应以 test_ 开头,并且应从 tests/__init__.py 导入,例如:

your_module
├── ...
├── tests
|   ├── __init__.py
|   ├── test_bar.py
|   └── test_foo.py

并且 __init__.py 包含:

from . import test_foo, test_bar

警告

未从 tests/__init__.py 导入的测试模块将不会运行

测试运行器将简单地运行任何测试用例,如官方 unittest documentation 所述,但 Odoo 提供了许多与测试 Odoo 内容(主要是模块)相关的实用工具和助手:

class odoo.tests.TransactionCase(methodName='runTest')[源代码]

测试类,其中所有测试方法都在单个事务中运行,但每个测试方法都在由保存点管理的子事务中运行。事务的游标始终在未提交的情况下关闭。

所有方法共用的数据设置应在类方法 setUpClass 中完成,以便对所有测试方法只执行一次。这对于包含快速测试但需要显著数据库设置的测试用例非常有用(复杂的数据库测试数据)。

每个测试方法运行后,都会清理记录缓存和注册表缓存。但是,不会清理注册表中的模型和字段。如果某个测试修改了注册表(自定义模型和/或字段),则应准备必要的清理(self.env.transaction.will_change_registry())。

browse_ref(xid)[源代码]

为提供的 external identifier 返回一个记录对象

参数

xid – 完全限定的 external identifier ,格式为 {模块}.{标识符}

抛出

如果未找到,则抛出 ValueError

返回

BaseModel

ref(xid)[源代码]

为提供的 external identifier 返回数据库 ID,是 _xmlid_lookup 的快捷方式

参数

xid – 完全限定的 external identifier ,格式为 {模块}.{标识符}

抛出

如果未找到,则抛出 ValueError

返回

已注册的 ID

class odoo.tests.HttpCase(methodName='runTest')[源代码]

带有 url_open 和 Chrome 无头助手的事务性 HTTP 测试用例。

browser_js(url_path, code, ready='', login=None, timeout=60, cookies=None, error_checker=None, watch=False, success_signal='test successful', debug=False, cpu_throttling=None, **kw)[源代码]

测试在浏览器中运行的 JavaScript 代码。

要表示测试成功,请使用预期的 success_signal 调用 console.log() 。默认值为 “test successful”。要表示测试失败,请抛出异常或使用消息调用 console.error 。如果未定义 error_checker 或对该消息返回 True ,则测试将在发生失败时停止。

参数
  • url_path (string) – 加载浏览器页面的 URL 路径

  • code (string) – 要执行的 JavaScript 代码

  • ready (string) – 在继续测试之前等待的 JavaScript 对象

  • login (string) – 将执行测试的登录用户,例如 ‘admin’、’demo’

  • timeout (int) – 等待测试完成的最大时间(以秒为单位)。默认值为 60 秒

  • cookies (dict) – 在加载页面之前要设置的 cookie 字典

  • error_checker – 用于过滤失败的函数。如果提供,则会用错误日志消息调用该函数,如果返回 False ,则忽略日志并继续测试。如果不提供,则每个错误日志都会触发失败。

  • watch (bool) – 打开一个新浏览器窗口以观察测试执行

  • success_signal (string) – 等待的成功信号字符串,用于判断测试是否成功

  • debug (bool) – 自动打开一个全屏 Chrome 窗口,附带已打开的开发者工具,并在游览开始时设置调试断点。游览运行时会带有 debug=assets 查询参数。当抛出错误时,调试器会在异常处停止。

  • cpu_throttling (int) – CPU 限制速率作为减速因子(1 表示无限制,2 表示 2 倍减速,依此类推)

browse_ref(xid)[源代码]

为提供的 external identifier 返回一个记录对象

参数

xid – 完全限定的 external identifier ,格式为 {模块}.{标识符}

抛出

如果未找到,则抛出 ValueError

返回

BaseModel

ref(xid)[源代码]

为提供的 external identifier 返回数据库 ID,是 _xmlid_lookup 的快捷方式

参数

xid – 完全限定的 external identifier ,格式为 {模块}.{标识符}

抛出

如果未找到,则抛出 ValueError

返回

已注册的 ID

odoo.tests.tagged(*tags)[源代码]

一个用于标记 BaseCase 对象的装饰器。

标签存储在一个集合中,可以通过 ‘test_tags’ 属性访问。

以 ‘-’ 为前缀的标签将移除该标签,例如移除 ‘standard’ 标签。

默认情况下,odoo.tests.common 中的所有 Test 类都有一个 test_tags 属性,其默认值为 ‘standard’ 和 ‘post_install’。

使用类继承时,标签会被继承。

最常见的做法是使用 TransactionCase 并在每个方法中测试模型的属性:

class TestModelA(TransactionCase):
    def test_some_action(self):
        record = self.env['model.a'].create({'field': 'value'})
        record.some_action()
        self.assertEqual(
            record.field,
            expected_field_value)

    # other tests...

注解

测试方法必须以 test_ 开头

class odoo.tests.Form(record: odoo.orm.models.BaseModel, view: None | int | str | odoo.orm.models.BaseModel = None)[源代码]

服务器端表单视图实现(部分)

实现大部分“表单视图”操作流程,使服务器端测试能够更准确地反映界面操作时的行为:

  • 在“创建”时调用相关的 onchange;

  • 在设置字段时调用相关的 onchange;

  • 正确处理 x2many 字段周围的默认值和 onchange。

保存表单将返回当前记录(如果是创建模式,则表示创建的记录)。它也可以通过 form.record 访问,但前提是表单没有未提交的更改。

常规字段可以直接分配给表单。对于 Many2one 字段,可以分配一个记录集:

# empty recordset => creation mode
f = Form(self.env['sale.order'])
f.partner_id = a_partner
so = f.save()

还可以将表单用作上下文管理器来创建或编辑记录。更改将在作用域结束时自动保存:

with Form(self.env['sale.order']) as f1:
    f1.partner_id = a_partner
    # f1 is saved here

# retrieve the created record
so = f1.record

# call Form on record => edition mode
with Form(so) as f2:
    f2.payment_term_id = env.ref('account.account_payment_term_15days')
    # f2 is saved here

对于 Many2many 字段,字段本身是一个 M2MProxy ,可以通过添加或删除记录来修改:

with Form(user) as u:
    u.group_ids.add(env.ref('account.group_account_manager'))
    u.group_ids.remove(id=env.ref('base.group_portal').id)

最后, One2many 被具体化为 O2MProxy 。

由于 One2many 仅通过其父级存在,因此可以通过 new() 和 edit() 方法创建“子表单”来直接操作。这些通常用作上下文管理器,因为它们会保存在父记录中:

with Form(so) as f3:
    f.partner_id = a_partner
    # add support
    with f3.order_line.new() as line:
        line.product_id = env.ref('product.product_product_2')
    # add a computer
    with f3.order_line.new() as line:
        line.product_id = env.ref('product.product_product_3')
    # we actually want 5 computers
    with f3.order_line.edit(1) as line:
        line.product_uom_qty = 5
    # remove support
    f3.order_line.remove(index=0)
    # SO is saved here
参数
  • record – 空记录集或单例记录集。空记录集会使视图从默认值进入“创建”模式,而单例记录集会使视图进入“编辑”模式并仅加载视图数据。

  • view – 用于触发 onchange 和视图约束的 ID、XMLID 或实际视图对象。如果未提供,则简单加载模型的默认视图。

12.0 新版功能.

save()[源代码]

保存表单(如有必要)并返回当前记录:

  • 不会保存 readonly 字段;

  • 不会保存未修改的字段(在编辑期间)—— 任何赋值或 onchange 返回都会将字段标记为已修改,即使设置为其当前值也是如此。

当无需保存时,仅返回当前记录。

引发

AssertionError – 如果表单中存在未填写的必填字段

property record

返回正在被表单编辑的记录。此属性是只读的,并且只能在表单没有待处理更改时访问。

class odoo.tests.M2MProxy(form, field_name)[源代码]

用于编辑多对多字段值的代理对象。

行为类似于 Sequence 的记录集,可以对其进行索引或切片以获取实际的基础记录集。

add(record)[源代码]

将 record 添加到字段中,该记录必须已经存在。

添加操作只有在父记录保存后才会最终完成。

remove(id=None, index=None)[源代码]

从字段中移除指定索引处或具有指定 ID 的记录。

clear()[源代码]

移除多对多字段中的所有现有记录

class odoo.tests.O2MProxy(form, field_name)[源代码]

用于编辑一对多字段值的代理对象。

new()[源代码]

返回一个新 One2many 记录的 Form ,并正确初始化。

如果列表视图可编辑,则从列表视图创建表单,否则从字段的表单视图创建。

引发

AssertionError – 如果字段不可编辑

edit(index)[源代码]

返回一个用于编辑现有 One2many 记录的 Form 。

如果列表视图可编辑,则从列表视图创建表单,否则从字段的表单视图创建。

引发

AssertionError – 如果字段不可编辑

remove(index)[源代码]

从父表单中移除索引为 index 的记录。

引发

AssertionError – 如果字段不可编辑

运行测试

如果在启动 Odoo 服务器时启用了 --test-enable ,则在安装或更新模块时会自动运行测试。

测试选择

在 Odoo 中,可以为 Python 测试添加标签,以便在运行测试时方便选择。

odoo.tests.BaseCase 的子类(通常通过 TransactionCase 或 HttpCase )默认会自动标记为 standard 和 at_install 。

调用

--test-tags 可用于在命令行中选择/过滤要运行的测试。它隐含了 --test-enable ,因此在使用 --test-tags 时无需指定 --test-enable 。

此选项默认值为 +standard ,意味着当使用 --test-enable 启动 Odoo 时,默认会运行标记为 standard 的测试(显式或隐式)。

在编写测试时,可以使用 tagged() 装饰器在 测试类 上添加或移除标签。

装饰器的参数是字符串形式的标签名称。

危险

tagged() 是一个类装饰器,对函数或方法没有影响。

可以通过加前缀减号( - )来 移除 标签,而不是添加或选择它们。例如,如果您不希望测试默认执行,可以移除 standard 标签:

from odoo.tests import TransactionCase, tagged

@tagged('-standard', 'nice')
class NiceTest(TransactionCase):
    ...

此测试默认不会被选中,要运行它需要显式选择相关标签:

$ odoo-bin --test-tags nice

请注意,只有标记为 nice 的测试会被执行。要同时运行 nice 和 standard 测试,请向 --test-tags 提供多个值:在命令行中,这些值是 累加的 (即选择具有 任意 指定标签的所有测试)。

$ odoo-bin --test-tags nice,standard

配置开关参数还接受 + 和 - 前缀。 + 前缀是隐含的,因此完全可选。 - (减号)前缀用于取消选择带有该前缀标签的测试,即使它们被其他指定标签选中。例如,如果有标记为 standard 的测试同时也标记为 slow ,您可以运行所有标准测试,但排除那些慢速测试:

$ odoo-bin --test-tags 'standard,-slow'

当您编写一个未继承自 BaseCase 的测试时,该测试将不会拥有默认标签,您必须显式添加这些标签以将其包含在默认测试套件中。这是一个常见的问题,尤其是在使用简单的 unittest.TestCase 时,因为它们不会被执行:

import unittest
from odoo.tests import tagged

@tagged('standard', 'post_install')
class SmallTest(unittest.TestCase):
    ...

除了标签之外,您还可以指定特定的模块、类或函数进行测试。 --test-tags 接受的完整语法格式如下:

[-][tag][/module][:class][.method]

因此,如果您想测试 stock_account 模块,可以使用:

$ odoo-bin --test-tags /stock_account

如果您想测试具有唯一名称的特定函数,可以直接指定:

$ odoo-bin --test-tags .test_supplier_invoice_forwarded_by_internal_user_without_supplier

这等同于

$ odoo-bin --test-tags /account:TestAccountIncomingSupplierInvoice.test_supplier_invoice_forwarded_by_internal_user_without_supplier

如果测试名称无歧义。可以一次指定多个模块、类和函数,用 , 分隔,类似于常规标签。

特殊标签

  • standard :所有继承自 BaseCase 的 Odoo 测试都会被隐式标记为 standard。 --test-tags 默认值也是 standard 。

    这意味着未标记的测试在启用测试时将默认执行。

  • post_install:表示测试将在所有模块安装完成后执行。这是默认的隐式标签。

  • at_install:表示测试将在模块安装后、其他模块安装之前立即执行。

    应极少使用此标签,因为它会阻止测试在 runbot 上并行执行。建议在测试上方添加一条注释,说明为何需要在其他模块安装之前运行。

    注意,此标签与 post_install 是 互斥 的,因此标记测试类时通常使用 -post_install 与 at_install 搭配。

示例

重要

测试仅在已安装的模块中执行。如果从干净的数据库开始,您需要至少使用 -i 开关安装模块。之后,除非需要升级模块(在这种情况下可以使用 -u ),否则不再需要此开关。为简化起见,以下示例中未指定这些开关。

仅运行来自 sale 模块的测试:

$ odoo-bin --test-tags /sale

运行来自 sale 模块的测试,但不包括标记为 slow 的测试:

$ odoo-bin --test-tags '/sale,-slow'

仅运行来自 stock 模块或标记为 slow 的测试:

$ odoo-bin --test-tags '-standard, slow, /stock'

注解

-standard 是隐式的(非必需),仅为清晰起见而存在

测试 JS 代码

测试复杂的系统是一项重要保障,用于防止回归并确保基本功能仍能正常工作。由于 Odoo 拥有相当庞大且复杂的 JavaScript 代码库,对其进行测试必不可少。

请参阅 单元测试 了解前端测试框架的各个方面,或直接跳转到其中一个子章节:

集成测试

分别测试 Python 代码和 JavaScript 代码非常有用,但这并不能证明 Web 客户端和服务器能够协同工作。为此,我们可以编写另一种测试:巡游(tours)。巡游是一个有趣的业务流程的小型场景。它描述了一系列应遵循的步骤。测试运行器将创建一个 PhantomJS 浏览器,将其指向正确的 URL,并根据场景模拟点击和输入操作。

编写测试巡游

结构

为 your_module 编写测试巡游时,首先需要创建所需的文件:

your_module
├── ...
├── static
|   └── tests
|       └── tours
|           └── your_tour.js
├── tests
|   ├── __init__.py
|   └── test_calling_the_tour.py
└── __manifest__.py

然后可以:

  • 更新 __manifest__.py ,将 your_tour.js 添加到资产中。

    'assets': {
        'web.assets_tests': [
            'your_module/static/tests/tours/your_tour.js',
        ],
    },
    
  • 更新 tests 文件夹中的 __init__.py ,以导入 test_calling_the_tour 。

JavaScript

  1. 通过注册来设置您的巡游。

    import tour from 'web_tour.tour';
    tour.register('rental_product_configurator_tour', {
        url: '/web',  // Here, you can specify any other starting url
    }, [
        // Your sequence of steps
    ]);
    
  2. 添加您想要的任何步骤。

每个步骤至少包含一个触发器。你可以使用 预定义步骤,也可以编写自己的个性化步骤。

以下是一些步骤示例:

Example

// First step
tour.stepUtils.showAppsMenuItem(),
// Second step
{
   trigger: '.o_app[data-menu-xmlid="your_module.maybe_your_module_menu_root"]',
   isActive: ['community'],  // Optional
   run: "click",
}, {
    // Third step
},

Example

{
    trigger: '.js_product:has(strong:contains(Chair floor protection)) .js_add',
    run: "click",
},

Example

{
    isActive: ["mobile", "enterprise"],
    content: "Click on Add a product link",
    trigger: 'a:contains("Add a product")',
    tooltipPosition: "bottom",
    async run(helpers) { //Exactly the same as run: "click"
      helpers.click();
    }
},

以下是您个性化步骤的一些可能参数:

  • trigger :必需,用于在某个元素上执行 run 操作的选择器/元素。巡游将在该元素存在且可见之前等待,然后再对其执行操作。

  • run :可选,在 trigger 元素上执行的操作。如果没有指定 run ,则不执行任何操作。

    操作可以是:

    • 一个异步函数,使用触发器的 Tip 作为上下文( this ),并以操作助手作为参数执行。

    • 操作助手之一的名称,它将在触发器元素上运行:

      check

      确保 trigger 元素被选中。此助手仅适用于 <input[type=checkbox]> 元素。

      clear

      清除 trigger 元素的值。此助手仅适用于 <input> 或 <textarea> 元素。

      click

      单击 trigger 元素,并执行所有相关的中间事件。

      dblclick,

      与 click 相同,但重复两次。

      drag_and_drop {target}

      模拟将 trigger 元素拖动到 target 的操作。

      edit {content}

      先 clear 元素,然后 fill 填充内容。

      editor {content}

      聚焦 触发 元素(wysiwyg),然后 按下 内容 。

      fill {content}

      聚焦 触发 元素,然后 按下 内容 。此辅助工具仅适用于 <input> 或 <textarea> 元素。

      悬停

      在 触发 元素上执行悬停操作序列。

      press {content}

      执行键盘事件序列。

      range {content}

      聚焦 触发 元素并将 内容 设置为值。此辅助工具仅适用于 <input[type=range]> 元素。

      select {value}

      在 触发 元素上执行选择事件序列。通过其 值 选择选项。此辅助工具仅适用于 <select> 元素。

      selectByIndex {index}

      与 select 相同,但通过其 索引 选择选项。注意,第一个选项的索引为 0。

      selectByLabel {label}

      与 select 相同,但通过其 标签 选择选项。

      取消选中

      确保 触发 元素未被选中。此辅助工具仅适用于 <input[type=checkbox]> 元素。

  • isActive :可选,仅当满足 isActive 数组的所有条件时激活步骤。- 浏览器处于 桌面 或 移动 模式。- 该巡游涉及 社区版 或 企业版 。- 巡游以 自动 (runbot)或 手动 (引导)模式运行。

  • tooltipPosition :可选, "顶部" 、 "右侧" 、 "底部" 或 "左侧" 。在运行交互式巡游时,提示框相对于 目标 的位置。

  • content :可选但推荐,交互式巡游中提示框的内容,同时也会记录到控制台,因此对于跟踪和调试自动化巡游非常有用。

  • timeout :步骤可以 运行 前需要等待的时间,单位为毫秒,默认为 10000(10 秒)。

重要

巡游的最后一步应始终将客户端返回到“稳定”状态(例如,没有正在进行的编辑),并确保所有副作用(网络请求)已完成运行,以避免在清理过程中出现竞争条件或错误。

Python

要从 Python 测试启动巡游,请使类继承自 HTTPCase ,并调用 start_tour :

def test_your_test(self):
    # Optional Setup
    self.start_tour("/web", "your_tour_name", login="admin")
    # Optional verifications

编写引导巡游

结构

要为 your_module 编写引导巡游,请先创建所需的文件:

your_module
├── ...
├── data
|   └── your_tour.xml
├── static/src/js/tours/your_tour.js
└── __manifest__.py

然后可以更新 __manifest__.py ,将 your_tour.js 添加到资源中,并将 your_tour.xml 添加到数据中。

'data': [
   'data/your_tour.xml',
],
'assets': {
    'web.assets_backend': [
        'your_module/static/src/js/tours/your_tour.js',
    ],
},

JavaScript

JavaScript 部分与 :ref: the test tour <testing/javascript/test> 相同。

XML

当您的巡游已在 JavaScript 注册表中时,可以在 XML 中创建一个 web_tour.tour 记录,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<odoo>
    <record id="your_tour" model="web_tour.tour">
        <field name="name">your_tour</field>
        <field name="sequence">10</field>
        <field name="rainbow_man_message">Congrats, that was a great tour</field>
    </record>
</odoo>
  • name :必需,名称必须与 JavaScript 注册表中的名称相同。

  • sequence :可选;确定执行引导巡游的顺序。默认为 1000。

  • url :可选;启动巡游的 URL。如果 url 为 False ,则从注册表中获取 URL。默认为 “/odoo” 。

  • rainbow_man_message :可选;在巡游完成时显示彩虹人效果中的消息。如果 rainbow_man_message 为 False ,则没有彩虹效果。默认为 <b>干得好!</b> 您已经完成了此巡游的所有步骤。

运行引导巡游

可以通过在用户菜单中切换 引导 选项,按照其顺序启动所有巡游。您还可以通过进入 设置 ‣ 技术 ‣ 用户界面 ‣ 巡游 并单击 引导 或 测试 来运行特定的引导巡游。

  • 引导 :将以交互模式执行巡游。这意味着巡游将显示需要执行的操作,并等待用户进行交互。

  • 测试 :将自动执行巡游。这意味着巡游将在用户面前执行所有步骤。

巡游录制器

您还可以使用巡游录制器轻松创建巡游。为此,请在引导巡游视图中单击 录制 。启动后,该工具将记录您在 Odoo 中的所有交互。

创建的巡游在引导巡游视图中标记为 自定义 。这些巡游还可以导出为 JavaScript 文件,以便放入您的模块中。

调试提示

在浏览器中观察测试巡游

有三种方法,各有优劣:

watch=True

当通过测试套件在本地运行巡游时,可以将 watch=True 参数添加到 browser_js 或 start_tour 调用中::

self.start_tour("/web", "your_tour_name", watch=True)

这将自动打开一个 Chrome 窗口,巡游将在其中运行。

优点
  • 如果巡游包含 Python 设置/外围代码或多个步骤,则始终有效

  • 完全自动运行(只需选择启动巡游的测试)

  • 事务性( 应该 始终能够多次运行)

缺点
  • 仅在本地工作

  • 仅在测试/巡游可以在本地正确运行时有效

debug=True

当通过测试套件在本地运行巡游时,可以将 debug=True 参数添加到 browser_js 或 start_tour 调用中::

self.start_tour("/web", "your_tour_name", debug=True)

这将自动打开一个全屏的 Chrome 窗口,同时打开开发者工具,并在巡游开始时设置调试器断点。巡游将以 debug=assets 查询参数运行。当抛出错误时,调试器会在异常处停止。

优点
  • 与 watch=True 模式具有相同的优点

  • 更容易调试步骤

缺点
  • 仅在本地工作

  • 仅在测试/巡游可以在本地正确运行时有效

通过浏览器运行

测试巡游也可以通过调用以下方式从浏览器界面启动:

odoo.startTour("tour_name");

在 JavaScript 控制台中,或者通过在 URL 中设置 ?debug=tests 来启用 测试模式 。

优点
  • 更容易运行

  • 可用于生产或测试站点,而不仅仅是本地实例

  • 允许以“引导”模式运行(手动步骤)

缺点
  • 对于涉及 Python 设置的测试巡游来说更难使用

  • 可能由于巡游的副作用而无法多次运行

小技巧

可以使用此方法观察或与需要 Python 设置的巡游进行交互:

  • 在相关巡游启动之前( start_tour 或 browser_js 调用)添加一个 Python 断点

  • 当命中断点时,在浏览器中打开实例

  • 运行巡游

此时,Python 设置将对浏览器可见,巡游将能够运行。

如果希望测试在之后继续运行(取决于巡游的副作用),您可能需要注释掉 start_tour 或 browser_js 调用。

在 browser_js 测试期间的截图和录屏

当从命令行运行使用 HttpCase.browser_js 的测试时,Chrome 浏览器将以无头模式运行。默认情况下,如果测试失败,将在失败时刻截取 PNG 截图并保存到

'/tmp/odoo_tests/{db_name}/screenshots/'

自 Odoo 13.0 起,新增了两个命令行参数来控制此行为: --screenshots 和 --screencasts

内省/调试步骤

当尝试修复/调试巡游时,失败时的截图可能并不足够。在这种情况下,查看某些或每个步骤中发生的情况可能会很有用。

虽然在“引导”模式下这相当容易(因为它们主要由用户显式驱动),但在运行“测试”巡游或通过测试套件运行巡游时会更复杂。在这种情况下,有两种主要技巧:

  • 在调试模式下(debug=True),步骤属性 break: true, 。

    这会在步骤开始时添加一个调试器断点。然后您可以根据需要自行添加。

    优点
    • 非常简单

    • 一旦恢复执行,巡游将继续

    缺点
    • 由于所有 JavaScript 被阻塞,页面交互受到限制

  • 在调试模式下(debug=True),步骤属性 pause: true, 。

    巡游将在步骤结束时停止。这允许开发人员检查和与页面交互,直到他们准备好通过在浏览器控制台中输入 play(); 来恢复。

    优点
    • 允许与页面交互

    • 没有无用(针对此情况)的调试器界面

  • 一个包含 run() { debugger; } 操作的步骤。

    这可以添加到现有步骤中,也可以是一个新的专用步骤。一旦步骤的 trigger 被匹配,执行将停止所有 JavaScript 执行。

    优点
    • 简单

    • 一旦恢复执行,巡游将继续

    缺点
    • 由于所有 JavaScript 被阻塞,页面交互受到限制

    • 在尝试查找步骤中定义的目标元素后触发调试器。

性能测试

查询计数

测试性能的一种方法是测量数据库查询。手动测试时,可以使用 --log-sql 命令行参数。如果要为某个操作设定最大查询数量,可以使用集成在 Odoo 测试类中的 assertQueryCount() 方法。

with self.assertQueryCount(11):
    do_something()