Существует множество способов протестировать приложение. В Odoo у мы используем три вида тестов
- python unit tests: useful for testing model business logic
- js unit tests: this is necessary to test the javascript code in isolation
- tours: this is a form of integration testing. The tours ensure that the python and the javascript parts properly talk to each other.
Тестирование кода Python
Odoo обеспечивает поддержку тестирования модулей с использованием 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.common.TransactionCase(methodName='runTest')[исходный код]
TestCase, в котором каждый тестовый метод запускается в своей транзакции и с собственным курсором. Откат транзакции и закрытие курсора после каждого теста.
browse_ref(xid)[исходный код]
Возвращает объект записи для предоставленного external identifier
module.identifier
BaseModel
ref(xid)[исходный код]
Возвращает ID базы данных для предоставленного external identifier, ярлык для get_object_reference
module.identifier
class odoo.tests.common.SingleTransactionCase(methodName='runTest')[исходный код]
TestCase, в которой все тестовые методы запускаются в одной транзакции, транзакция запускается с помощью первого метода тестирования и откатывается в конце последнего.
browse_ref(xid)[исходный код]
Возвращает объект записи для предоставленного external identifier
module.identifier
BaseModel
ref(xid)[исходный код]
Возвращает ID базы данных для предоставленного external identifier, ярлык для get_object_reference
module.identifier
class odoo.tests.common.SavepointCase(methodName='runTest')[исходный код]
Аналогичен SingleTransactionCase
в том, что все методы тестирования выполняются в одной транзакции, но каждый TestCase выполняется в откатанной точке сохранения (под-транзакции).
Полезно для тестовых случаев, содержащих быстрые тесты, но со значительной настройкой базы данных, общей для всех случаев (сложные тестовые данные в бд): :meth:`~.setUpClass`может использоваться для генерации тестовых данных БД один раз и тогда все TestCase будут использовать одни и те же данные, не влияя друг на друга, и без необходимости заново создавать тестовые данные.
class odoo.tests.common.HttpCase(methodName='runTest')[исходный код]
Транзакционный HTTP TestCase с url_open и Chrome headless инструментами.
browse_ref(xid)[исходный код]
Возвращает объект записи для предоставленного external identifier
module.identifier
BaseModel
phantom_js(url_path, code, ready='', login=None, timeout=60, **kw)[исходный код]
Протируетjs код запустив его в браузере - дополнительно авторизуется в системе как login, загрузит объявленную страницу url_path, дождется пока объект сможет быть выполнен и исполнит code внутри страницы
To signal success test do: console.log(„ok“)
To signal failure do: console.log(„error“)
If neither are done before timeout test fails.
ref(xid)[исходный код]
Возвращает ID базы данных для предоставленного external identifier, ярлык для get_object_reference
module.identifier
odoo.tests.common.tagged(*tags)[исходный код]
Декоратор для тегирования объектов BaseCase, Теги хранятся в сете, доступ к которому можно получить из атрибута «test_tags». Тег с префиксом «-» удалит тег, например, удалить тег standard. По умолчанию все классы тестов из odoo.tests.common имеют атрибут test_tags, который по умолчанию равен standard, а также техническое имя модуля. При использовании наследования классов теги НЕ наследуются.
По умолчанию тесты запускаются сразу после установки соответствующего модуля. Но можно настроить, чтобы тестирование запускалось после установки всех модулей, а не после установки одного модуля:
odoo.tests.common.at_install(flag)[исходный код]
Устанавливает состояние at-install для теста, флаг является логическим значением, указывающим, должен ли тест (True
) или не должен (False
) выполняться во время установки модуля.
По умолчанию тесты запускаются сразу после установки модуля перед началом установки следующего модуля.
Не рекомендуется, начиная с версии 12.0: at_install
еперь флаг, вы можете использовать tagged()
чтобы добавить/удалить его, более того tagged
работает только на классах тестов
odoo.tests.common.post_install(flag)[исходный код]
Устанавливает состояние после установки теста. Флаг является логическим параметром, определяющим, должен ли тест запускаться или не запускаться после установки набора модулей.
По умолчанию тесты не запускаются после установки всех модулей в текущем наборе для.
Не рекомендуется, начиная с версии 12.0: post_install
теперь флаг, вы можете использовать tagged()
для того, чтобы добавить/удалить его, а так же tagged
работает только на классах тестов
Наиболее распространенная ситуация заключается в использовании TransactionCase
и тестирования свойства модели в каждом методе:
class TestModelA(common.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.common.Form(recordp, view=None)[исходный код]
Реализация представления Form на стороне сервера (частично)
Реализует большую часть процесса для работы с «представлением Form», так что тесты на стороне сервера могут правильнее отражать поведение, которое наблюдается при работе с интерфейсом:
- вызовите default_get и соответствующие изменения на «создание»
- вызовите соответствующие onchanges к настройкам полей
- правильно обработайте defaults и onchanges для x2many полей
Сохранение формы возвращает созданную запись в режиме «creation».
Регулярные поля могут быть просто назначены непосредственно в форме, для полей Many2one
назначается одноэлементный набор записей
# empty recordset => creation mode
f = Form(self.env['sale.order'])
f.partner_id = a_partner
so = f.save()
При редактировании записи используйте Form в качестве диспетчера контекста, чтобы автоматически сохранить ее в конце области:
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.groups_id.add(env.ref('account.group_account_manager'))
u.groups_id.remove(id=env.ref('base.group_portal').id)
И наконец поле One2many
это класс O2MProxy
.
Поскольку класс One2many
существует только через своего родителя, он более непосредственно управляется путем создания sub-forms с помощью new()
и edit()
методов. Обычно они используются в качестве менеджеров контекста, так как они сохраняются в родительской записи:
with Form(so) as f3:
# 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
- recordp (
odoo.models.Model
) – пустой или одиночный набор записей. Пустой набор записей переведет представление в режим «creation» и вызовет вызовы default_get и on-load onchanges, синглтон переведет его в режим «редактирования» и загрузит только данные представления. - view (
int | str | odoo.model.Model
) – id, xmlid или фактический объект представления, чтобы использовать для onchanges и ограничений представления. Если ничего не указано, просто загружается представление по умолчанию для модели.
Добавлено в версии 12.0.
save()[исходный код]
Сохраняет форму, возвращает созданную запись, если применимо
- не сохраняет поля
readonly
- не сохраняет неизмененные поля (во время редактирования) - любое присвоение или возвращение onchange помечает поле как измененное, даже если установлено его текущее значение
class odoo.tests.common.M2MProxy[исходный код]
Ведет себя как Sequence
наборов записей, может быть проиндексирован или к нему может быть применен метод slice для получения актуальных наборов записей.
add(record)[исходный код]
Добавляет record
к полю, запись должна уже существовать.
Добавление будет завершено только после сохранения родительской записи.
clear()[исходный код]
Удаляет все существующие записи m2m
remove(id=None, index=None)[исходный код]
Удаляет запись с определенным индексом или с указанным идентификатором из поля.
class odoo.tests.common.O2MProxy[исходный код]
edit(index)[исходный код]
Возвращает Form
для редактирования существующей записи One2many
.
Форма создается из представления списка, если он доступен для редактирования, или в противном случае из формы поля.
new()[исходный код]
Возвращает класс Form
для новой One2many
,правильно инициализированной,записи.
Форма создается из представления списка, если он доступен для редактирования, или в противном случае из формы поля.
remove(index)[исходный код]
Удаляет запись в index
из родительской формы.
Выполнение тестов
Тесты автоматически запускаются при установке или обновлении модулей, если опция --test-enable
была включена при запуске сервера Odoo.
Выбор теста
В Odoo тесты Python могут быть помечены тегом для облегчения выбора тестов при их запуске.
Подклассы odoo.tests.common.BaseCase
(обычно через TransactionCase
, SavepointCase
или HttpCase
) автоматически помечаются как standard
, at_install
и именем их исходного модуля по умолчанию.
Введение
--test-tags
может использоваться для выбора/фильтрации тестов для запуска с помощью командной строки.
Эта опция по умолчанию имеет значение +standard
что означает, что тесты с тегом standard
(явно или неявно) будут запускаться по умолчанию при запуске Odoo с параметром --test-enable
.
При написании тестов декоратор tagged()
можно использовать в классах тестов для добавления или удаления тегов.
Аргументы декоратора - это имена тегов в виде строк.
Опасно
tagged()
декоратор класса, он не влияет на функции или методы
Тэги могут иметь префикс со знаком минус (-
) чтобы удалить их вместо добавления, например. если вы не хотите, чтобы ваш тест выполнялся по умолчанию, вы можете удалить тег standard
:
from odoo.tests import TransactionCase, tagged
@tagged('-standard', 'nice')
class NiceTest(TransactionCase):
...
Этот тест не будет выбран по умолчанию, т.к. для его запуска соответствующий тег должен быть выбран явно:
$ odoo-bin --test-enable --test-tags nice
Обратите внимание, что будут выполняться только тесты с тегом nice
. Для запуска обоих * ``nice`` и ``standard`` тестов укажите несколько значений для :option:`–test-tags <odoo-bin –test-tags>`: в командной строке, значения этого параметра являются *аддитивными (вы выбираете все тесты с любым из указанных тегов)
$ odoo-bin --test-enable --test-tags nice,standard
Параметр также принимает префиксы + `` и ``-
. Префикс + `` подразумевается и, следовательно, его указывать не обязательно. Префикс ``-
(минус) предназначен для отмены выбора тестов, помеченных префиксными тегами, даже если они выбраны другими указанными тегами, например, если есть standard
тесты, которые также помечены как slow
, вы можете запустить все стандартные тесты ,*за исключением* медленных:
$ odoo-bin --test-enable --test-tags 'standard,-slow'
Когда вы пишете тест, который не наследуется от BaseCase
, этот тест не будет иметь тегов по умолчанию, вы должны добавить их явно, чтобы тест был включен в набор тестов по умолчанию , Это распространенная проблема при использовании простого unittest.TestCase
, поскольку они не просто не запускаются:
import unittest
from odoo.tests import tagged
@tagged('standard', 'at_install')
class SmallTest(unittest.TestCase):
...
Примеры
Важно
Тесты будут выполняться только в установленных или обновленных модулях. Поэтому модули нужно выбирать с помощью парметеров -u
или -i
. Для простоты эти параметры не указаны в приведенных ниже примерах.
Запускает тесты из модуля sale:
$ odoo-bin --test-enable --test-tags sale
Запускает тесты из модуля sale кроме тех, которые имеют тег slow:
$ odoo-bin --test-enable --test-tags 'sale,-slow'
Запускает тесты из модуля stock имеющие тег slow:
$ odoo-bin --test-enable --test-tags '-standard, slow, stock'
Примечание
``-standard``является неявным (не обязательным) и указан для наглядности
Тестирование JS кода
Инструмент для тестирования Qunit
Odoo Web includes means to unit-test both the core code of Odoo Web and your own javascript modules. On the javascript side, unit-testing is based on QUnit with a number of helpers and extensions for better integration with Odoo.
To see what the runner looks like, find (or start) an Odoo server
with the web client enabled, and navigate to /web/tests
This will show the runner selector, which lists all modules with javascript
unit tests, and allows starting any of them (or all javascript tests in all
modules at once).
Clicking any runner button will launch the corresponding tests in the bundled QUnit runner:
Writing a test case
This section will be updated as soon as possible.
Интеграционное тестирование
Тестирование кода Python и кода JS по отдельности очень полезно, но это не доказывает, что веб-клиент и сервер работают вместе. Чтобы сделать это, мы можем написать другой вид теста: туры. Тур - это мини-сценарий описывающи бизнес-процесс. Он объясняет последовательность шагов, которые должны быть выполнены. Затем организатор теста создаст браузер phantom_js, укажет ему правильный URL-адрес и смоделирует клики и ввод данных в соответствии со сценарием.