← ClaudeAtlas

odoo-testinglisted

Proving an Odoo customization works before merge — writing and running Python tests for models, method overrides, computed fields, onchange, constraints, security, and cross-addon flows. Use after any server-side change (new field, overridden create/write, compute/constrains, ACL or record-rule edit) and when deciding the base class, at_install vs post_install tags, or how to test non-admin / multi-company / batch / onchange behavior. A patch isn't done until a test fails before it and passes after. The test gate for the odoo-dev skill. Targets Odoo 17/18/19.
tuanle96/odoo-ai-skills · ★ 4 · Testing & QA · score 62
Install: claude install-skill tuanle96/odoo-ai-skills
# Odoo testing — the gate The `odoo-introspect` skill stops the agent guessing; this stops the patch silently breaking something else. **A customization isn't done until it's proven.** Require all of this before submitting or merging. **Version floor: Odoo 17/18, through Odoo 19 (current LTS).** The class/decorator names below are v17/18; for v16 and older see `skills/odoo-introspect/references/version-matrix.md`. Note newer **online** versions don't load demo data by default — don't rely on a demo record existing in a test; create what you assert on. ## Where tests live Python tests go in a `tests/` subpackage, **imported from `tests/__init__.py`** — Odoo only collects tests that are imported. The package loads only when the module is installed/updated with `--test-enable`. ``` my_module/ ├── __init__.py └── tests/ ├── __init__.py # from . import test_sale_confirm └── test_sale_confirm.py ``` ## Base classes — pick by what you drive | Class | Import | Use for | |-------|--------|---------| | `TransactionCase` | `odoo.tests.common` | The default. Each test method runs in its own savepoint, rolled back after. Shared data in `setUpClass`. | | `Form` | `odoo.tests.common` | Drive a record **through the UI's onchange engine** — the only way to exercise `@api.onchange` from Python. | | `HttpCase` | `odoo.tests.common` | Controllers, and JS **tours** via `self.start_tour(...)`. Runs headless Chrome. | > `SavepointCase` is **gone** (merged into `TransactionC