diff --git a/tests/README.md b/tests/README.md
new file mode 100644
index 0000000..b1b23cc
--- /dev/null
+++ b/tests/README.md
@@ -0,0 +1,184 @@
+# Testing & Quality Assurance Documentation
+
+This document outlines the testing strategy, tools and workflows used to ensure the reliability and quality of Perry's Odoo custom addons.
+
+Our testing architecture relies heavily on **Pytest** for both unit and integration tests, custom Odoo module mocking, strict pre-commit hooks and automated CI/CD pipelines.
+
+---
+
+## Testing stack
+
+We use a Python testing stack defined in `requirements.txt`:
+
+* **[`pytest`](https://docs.pytest.org/)**: The core testing framework.
+* **[`pytest-asyncio`](https://pytest-asyncio.readthedocs.io/)**: For testing asynchronous code (`async`/`await`).
+* **[`pytest-mock`](https://pytest-mock.readthedocs.io/)**: For mocking dependencies and isolating tests (using `monkeypatch` and `Mock`).
+* **[`pytest-cov`](https://pytest-cov.readthedocs.io/)**: To measure code coverage.
+* **[`pytest-dotenv`](https://pypi.org/project/pytest-dotenv/)**: To automatically load `.env` variables during tests.
+* **[`pytest-testdox`](https://pypi.org/project/pytest-testdox/)**: To generate human-readable terminal output for test results.
+
+Additionally, **code quality** is enforced by **[`Ruff`](https://docs.astral.sh/ruff/)** (linter/formatter) and **[`Safety`](https://github.com/pyupio/safety)** (dependency vulnerability scanner).
+
+---
+
+## Directory structure
+
+The `tests` directory is organized by Odoo module to mirror the structure of the `custom_addons` folder. This makes it easy to locate the tests for any given feature.
+
+
+

+
Structure of the tests/ directory
+
+
+* **`perry_auto_reply/`**: Tests for the automated reply logic and user configurations (`test_res_users_perry.py`). No used anymore for main functionalities.
+* **`perry_human_loop/`**: Tests for pending actions, summary computations, logfire configuration and action execution (e.g., creating leads, payments, calendar events).
+* **`perry_webhook/`**: Tests for the webhook ingestion endpoints and their respective telemetry.
+* **`conftest.py`**: Global test configuration and Odoo environment mocking.
+
+---
+
+## Configuration and Fixtures
+
+### `pytest.ini`
+Our Pytest configuration ensures correct test discovery and handles asynchronous modes automatically:
+```ini
+[pytest]
+asyncio_mode = auto
+testpaths = tests
+python_files = test_*.py
+pythonpath = .
+```
+
+### Global Odoo Mocking (`conftest.py`)
+Testing Odoo modules usually requires a full database and server environment. To make our tests fast, reliable and isolated, we use a **custom mocking strategy** in `conftest.py`:
+
+* **`install_odoo_mock()`**: Intercepts the `import odoo` statements during the test collection phase. It dynamically creates fake Python modules (`odoo.models`, `odoo.fields`, `odoo.api`, `odoo.exceptions`) so our addon files can be imported without raising a `ModuleNotFoundError`.
+* **`mock_odoo_modules` (autouse fixture)**: Re-installs the clean mock environment before every single test, ensuring absolute isolation.
+* **Fake classes**: We use `FakeModel`, `FakeRecord` and `FakePendingAction` inside our test files to simulate Odoo's Active Record pattern (like `.create()`, `.sudo()`, and `.search()`) directly in memory.
+
+---
+
+## Running the tests
+
+We use a `Makefile` to simplify the execution of test commands from the terminal.
+
+> **Important:** All `make` commands must be executed from the root of the repository.
+
+1. **Run all tests (with readable output):**
+ ```bash
+ make test
+ ```
+ *Executes: `pytest --testdox tests/`*
+
+ 
+ *Example output of a successful `make test` run*
+
+2. **Run tests with Coverage Report:**
+ ```bash
+ make test-cov
+ ```
+ *Executes: `pytest --cov=custom_addons --testdox tests/`*
+
+ 
+ *Terminal output displaying the test coverage summary*
+
+---
+
+## Pre-commit hooks
+
+Before any code is committed, we enforce quality checks using `.pre-commit-config.yaml`. The pipeline ensures that broken code never reaches the repository.
+
+The hooks run in this order:
+1. **Ruff Check**: Lints the code for syntax and style errors.
+2. **Ruff Format**: Automatically formats the Python code.
+3. **Safety Scan**: Checks for known vulnerabilities in the installed dependencies.
+4. **Run Tests**: Executes the full Pytest suite (`bash -c "PYTHONPATH=. pytest"`). The commit will be aborted if any test fails.
+
+---
+
+## Continuous Integration (GitHub Actions)
+
+We use GitHub Actions to run our test suite automatically on the cloud whenever code is pushed to or merged into the `main` branch. This guarantees that integrations don't break existing features.
+
+
+*Successful test workflow execution in GitHub Actions*
+
+The workflow (`.github/workflows/tests.yml`) sets up Python 3.10, installs the requirements and runs Pytest:
+
+```yaml
+name: Run tests
+
+on:
+ push:
+ branches: ["main", "master"]
+ pull_request:
+ branches: ["main", "master"]
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Set up Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: "3.10"
+
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install -r requirements.txt
+
+ - name: Run tests
+ run: |
+ PYTHONPATH=. pytest
+```
+
+---
+
+## Guide: How to add tests for a new Odoo feature
+
+If you are creating a new feature or model inside `custom_addons/`, you must ensure it is covered by tests. Because we mock the Odoo environment, you will rely on custom Fake classes. Follow these steps:
+
+### Step 1: Create the test file
+Navigate to the corresponding folder inside `tests/` (e.g., `tests/perry_human_loop/`) and create a new file. **The file name must start with `test_`**:
+`test_new_feature.py`
+
+### Step 2: Import dependencies and test utilities
+Import `pytest`, `Mock` (if needed), and the fake Odoo helpers you need from your test suite context.
+
+### Step 3: Write the tests using memory models
+* Start the function name with `test_`.
+* Use standard Python dictionaries and instances of `FakeRecord` to represent Odoo records.
+* Pass these fake objects into the logic you want to test.
+
+**Example (Testing an action execution):**
+```python
+import pytest
+from custom_addons.perry_human_loop.models.perry_pending_action import PerryPendingAction
+
+# Assuming FakeRecord and FakePendingAction are defined locally or imported
+def test_action_cancel_marks_records_as_cancelled():
+ """Test that cancelling an action updates the state of multiple records."""
+
+ # 1. Arrange (Setup fake records in memory)
+ first = FakeRecord(state="draft")
+ second = FakeRecord(state="pending")
+ action = FakePendingAction([first, second])
+
+ # 2. Act (Trigger the method)
+ result = action.action_cancel()
+
+ # 3. Assert (Verify Odoo-like behavior)
+ assert result == {"type": "ir.actions.client", "tag": "reload"}
+ assert first.state == "cancelled"
+ assert second.state == "cancelled"
+```
+
+### Step 4: Run and verify
+Run `make test` or `make test-cov` locally to ensure the new tests pass.
+
+Once you try to commit, the pre-commit hook will also validate the work automatically.
diff --git a/tests/img/github-actions-odoo.png b/tests/img/github-actions-odoo.png
new file mode 100644
index 0000000..6f5e5c4
Binary files /dev/null and b/tests/img/github-actions-odoo.png differ
diff --git a/tests/img/make-test-cov-odoo.png b/tests/img/make-test-cov-odoo.png
new file mode 100644
index 0000000..2e632ac
Binary files /dev/null and b/tests/img/make-test-cov-odoo.png differ
diff --git a/tests/img/make-test-odoo.png b/tests/img/make-test-odoo.png
new file mode 100644
index 0000000..98b6032
Binary files /dev/null and b/tests/img/make-test-odoo.png differ
diff --git a/tests/img/tests_structure-odoo.png b/tests/img/tests_structure-odoo.png
new file mode 100644
index 0000000..9122b6b
Binary files /dev/null and b/tests/img/tests_structure-odoo.png differ