Odoo 编写 Python代码测试用例

Odoo 编写 Python代码测试用例

odoo.test模块提供了一组用于编写单元测试和功能测试的工具和类。使用这些工具和类,开发人员可以编写各种类型的测试用例,以验证Odoo模块的正确性和稳定性。

odoo.test模块的主要特点和功能包括:

  1. 支持单元测试和功能测试:odoo.test模块允许开发人员编写单元测试和功能测试,以验证模块的各个部分的行为和功能。

  2. 提供测试基类:odoo.test模块提供了一些测试基类,可以继承并使用其中的方法来编写测试用例。

  3. 数据库事务管理:odoo.test模块使用数据库事务来管理测试用例的数据,以确保每个测试用例在一个独立的环境中运行。

  4. 断言方法:odoo.test模块提供了一组断言方法,用于验证测试结果是否符合预期。

  5. 测试装置:odoo.test模块提供了一些测试装置,用于模拟和控制测试环境中的各种情况和条件。

Odoo.test编写测试用例

详细介绍请参考Testing Odoo官方文档。

目录结构

Odoo项目是由每个模块组成的,测试用例编写在每个模块内,在模块内创建tests文件夹,每个测试用例以test_*.py方式命名,创建测试用例结构如下:

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

__init__.py 添加内容:

from . import test_foo, test_bar

主要测试基类和工具类

odoo.test.common中有一些常用的测试基类和工具类,用于编写测试用例。

  1. TransactionCase

    • TransactionCase是一个测试基类,用于编写功能测试用例。
    • 它继承自unittest.TestCase类,并添加了Odoo框架的特定功能。
    • TransactionCase类使用数据库事务来管理测试用例的数据,以确保每个测试用例在一个独立的环境中运行。
  2. SavepointCase

    • SavepointCaseTransactionCase的子类,提供了更高级的数据库事务管理功能。
    • 它在每个测试用例之前创建一个保存点,并在测试用例运行结束后回滚到该保存点,以确保测试用例之间的数据隔离性。
  3. HttpCase

    • HttpCase是一个测试基类,用于编写HTTP请求的功能测试用例。
    • 它继承自TransactionCase类,并添加了模拟HTTP请求和处理的功能。
  4. SingleTransactionCase

    • SingleTransactionCase是一个测试基类,用于编写单个数据库事务中的测试用例。
    • 它继承自TransactionCase类,并在每个测试用例之前创建一个数据库事务,并在测试用例运行结束后回滚该事务。

SavepointCase类

Safeguard your code with unit tests官方文档

SavepointCase使用数据库事务来管理测试用例的数据,但它使用了更高级的保存点(savepoint)机制。 在每个测试用例运行之前,SavepointCase会创建一个保存点,并在测试用例运行结束后回滚到该保存点。这样,测试用例之间可以共享一部分数据状态,而不需要完全重置数据。SavepointCase适用于测试用例之间需要共享一些数据状态的情况,以减少数据重置的开销。

所以在编写测试用历史更推荐使用SavepointCase作为一个模块的各个测试用例的数据初始化。

tests文件夹下创建一个common.py文件。

from odoo.tests.common import SavepointCase
from odoo.tests import tagged

# The CI will run these tests after all the modules are installed,
# not right after installing the one defining it.
@tagged('at_install')
class YourModelTestCase(SavepointCase):

    
    @classmethod
    def setUpClass(cls):
        # add env on cls and many other things
        super(YourModelTestCase, cls).setUpClass()

        # create the data for each tests. By doing it in the setUpClass instead
        # of in a setUp or in each test case, we reduce the testing time and
        # the duplication of code.

        # 只会在整个测试类中的第一个测试方法执行前调用一次。

        #  创建测试用户
        user_model = 'res.users'
        cls.your_model= 'name.your_model'
        cls.exclude_user = cls.env[user_model].search([('login', '=', 'admin')], limit=1)
        cls.other_user = cls.env[user_model].search([('login', '!=', 'admin')], limit=1)

        exclude_records = [
            {'exclude_type': 'User', 'user_id': cls.exclude_user.id}
        ]
        
        cls.env[cls.your_model].create(exclude_records)

from odoo.tests import tagged简介:

官方链接: invocation

@tagged装饰器可以用于特定的测试场景。以下是一些常用的内置测试标签:

  1. at_install :表示测试用例在安装模块时运行。
  2. post_install :表示测试用例在安装模块后运行。
  3. standard :表示标准测试用例,通常在模块的 tests 目录中找到。

也可以在测试用例中使用多个标签,以便更好地组织和选择性地运行测试。
命令行中使用方法:[-][tag][/module][:class][.method]

同时也可以用@tagged装饰器在class上自定义标签,通过自定的标签来执行要测试(或要排除)的测试用例。

编写测试用例

tests目录下创建测试用例文件test_model_exclude_setting.pyTestYourModelExcludeSetting类集成我们刚才创建的common.YourModelTestCase类,就可以使用YourModelTestCase中初始化的测试数据。

当此测试用例需要其他的测试数据,可以在setUp(self)中初始化。

每个单独的测试方法建议使用test_01_xxx方式创建,因为unitest是根据方法名称的排序执行的,所以test后面跟数字命名来保证测试方法的执行顺序。


# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from . import common

class TestYourModelExcludeSetting(common.YourModelTestCase):


    def setUp(self):
        # 初始化数据准备
        # 每个测试方法都会在执行前都会调用一次 setUp() 方法
        return super(TestYourModelExcludeSetting, self).setUp()


    def get_record_counts(self, domain):
        return self.env[self.your_model].get_records_count(domain)


    def test_01_get_record_counts(self):
        '''
            验证get_record_counts方法返回记录是否正确
        '''

        # 根据创建排除的测试用户获取记录条数
        exclude_user_record_count = self.get_record_counts(
            [('exclude_type', '=', 'User'), ('user_id', '=', self.exclude_user.id)]
        )
        self.assertTrue(exclude_user_record_count > 0, 
                        f'Can not find exclude user: {self.exclude_user.name}')


    def test_02_menu_check_exclude(self):
        '''
            check_exclude方法验证输入菜单是否被屏蔽
        '''
        ...
        
        

断言

断言是测试用例中判断测试结果是否成功的关键,下面是odoo.tests中一些断言的使用方法介绍。

在Odoo的测试中,我们可以使用多种断言方法来验证预期结果和实际结果是否匹配。以下是一些常用的断言方法及其说明:

  1. assertEqual(a, b, msg=None) :验证a和b是否相等。如果不相等,将引发AssertionError异常。可以使用 msg 参数来自定义错误消息。

  2. assertNotEqual(a, b, msg=None) :验证a和b是否不相等。如果相等,将引发AssertionError异常。可以使用 msg 参数来自定义错误消息。

  3. assertTrue(x, msg=None) :验证x是否为True。如果x为False,将引发AssertionError异常。可以使用 msg 参数来自定义错误消息。

  4. assertFalse(x, msg=None) :验证x是否为False。如果x为True,将引发AssertionError异常。可以使用 msg 参数来自定义错误消息。

  5. assertIs(a, b, msg=None) :验证a和b是否是同一个对象。如果不是同一个对象,将引发AssertionError异常。可以使用 msg 参数来自定义错误消息。

  6. assertIsNot(a, b, msg=None) :验证a和b是否不是同一个对象。如果是同一个对象,将引发AssertionError异常。可以使用 msg 参数来自定义错误消息。

  7. assertIsNone(x, msg=None) :验证x是否为None。如果x不为None,将引发AssertionError异常。可以使用 msg 参数来自定义错误消息。

  8. assertIsNotNone(x, msg=None) :验证x是否不为None。如果x为None,将引发AssertionError异常。可以使用 msg 参数来自定义错误消息。

  9. assertIn(a, b, msg=None) :验证a是否在b中。如果a不在b中,将引发AssertionError异常。可以使用 msg 参数来自定义错误消息。

  10. assertNotIn(a, b, msg=None) :验证a是否不在b中。如果a在b中,将引发AssertionError异常。可以使用 msg 参数来自定义错误消息。

执行测试用例

coverage参数说明:

coverage是一个用于测试代码覆盖率的Python库。它可以帮助你了解你的测试用例是否覆盖了源代码的各个部分。下面是一些常用的coverage命令参数的说明:

  • run :运行测试用例并收集代码覆盖率数据。
  • --source=<source> :指定要收集覆盖率数据的源代码目录或模块。
  • --omit=<patterns> :指定要忽略的文件或目录的模式。可以使用通配符来匹配多个文件或目录。
  • --include=<patterns> :指定要包含在覆盖率报告中的文件或目录的模式。同样可以使用通配符来匹配多个文件或目录。
  • report :生成代码覆盖率报告。
  • html :生成HTML格式的代码覆盖率报告。
  • xml :生成XML格式的代码覆盖率报告。

以下是一个示例命令,用于运行测试用例并生成HTML格式的代码覆盖率报告:

coverage run --source=my_module -m unittest discover
coverage html

这将运行名为"my_module"的模块的测试用例,并生成一个名为"htmlcov"的文件夹,其中包含了HTML格式的代码覆盖率报告。

请注意,以上只是coverage的一些常用参数说明,可以通过运行 coverage --help 命令来查看更多参数选项和详细说明。

生成测试报告

使用coverage检测测试代码覆盖率并执行测试用例,安装coverage:pip install coverage

coverage run --source='project\addons\your_model' odoo\odoo-bin -c project_dev.conf --test-tags=your_model -u your_model

查看代码覆盖率

coverage report -m

Name                                                                               Stmts   Miss  Cover   Missing
----------------------------------------------------------------------------------------------------------------
project\addons\your_model\__init__.py                            2      0   100%
project\addons\your_model\__manifest__.py                        1      1     0%   2
project\addons\your_model\controllers\__init__.py                1      0   100%
project\addons\your_model\controllers\controllers.py             0      0   100%
project\addons\your_model\models\__init__.py                     1      0   100%
project\addons\your_model\models\models.py                      98     27    72%   27-40, 45-47, 67-77, 143
project\addons\your_model\tests\__init__.py                      1      0   100%
project\addons\your_model\tests\common.py                       18      0   100%
project\addons\your_model\test_model_exclude_setting.py         50      0   100%
----------------------------------------------------------------------------------------------------------------
TOTAL                                                          172     28    84%

生成测试报告coverage html命令默认会在当前目录下生成一个名为"htmlcov"的文件夹,其中包含了HTML格式的代码覆盖率报告。

如果你希望将生成的报告放在指定的位置,可以使用 --directory 参数指定目标目录。以下是示例命令

coverage html --directory=/path/to/target/directory

总结

本章很详细的介绍了Odoo项目中测试用例的编写方法,希望大家多进行尝试和阅读官方文档。在实际编写测试用例之前也是认为并没有多大的用处,但是实际执行时就会暴露我们想不到的问题,可以提前解决项目中隐藏的问题,所以希望我们尽量多写测试用例,同时结合coverage命令查询测试用例覆盖率,尽可能覆盖我们的业务逻辑,在问题发生之前提前解决隐患。

在上述测试用例中我们只使用了SavepointCase基类,也是使用最多的一个,还有常用的TransactionCaseSingleTransactionCase后面也会介绍。这些基类最大的不同是在于事务的范围不一样,大家可以根据官方文档和上面说明自己编写测试用例进行验证。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我在那路边

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值