Ir al contenido

Testing en Odoo: unit tests, mocks y env.ref()

Cómo escribir tests fiables, preparar datos de prueba y evitar falsos positivos
11 de julio de 2026 por
Testing en Odoo: unit tests, mocks y env.ref()
Atemi, Aitor Atencia

Odoo · Testing · Calidad

Un test que pasa siempre, incluso cuando rompes el código que debería cubrir, es peor que no tener test: da una falsa sensación de seguridad. En Odoo, la mayoría de falsos positivos vienen de preparar mal los datos de prueba, no de un mal assert.

Logo Odoo
TransactionCase hace rollback automático: cada test empieza en un estado limpio.

La base

TransactionCase: aislamiento real entre tests

Cada método de test en TransactionCase corre dentro de una transacción que se revierte al terminar. Esto significa que un test nunca debería depender del orden de ejecución ni dejar basura para el siguiente: si lo hace, es síntoma de que está asumiendo datos que no creó él mismo.

# tests/test_documento.py
from odoo.tests.common import TransactionCase

class TestDocumento(TransactionCase):
    def setUp(self):
        super().setUp()
        self.partner = self.env["res.partner"].create({"name": "Cliente Test"})

    def test_confirmar_documento(self):
        doc = self.env["mi_modulo.documento"].create({"partner_id": self.partner.id})
        doc.action_confirm()
        self.assertEqual(doc.state, "confirmed")

El error más común

No dependas de datos demo ni de env.ref() a ciegas

Un test que hace self.env.ref("base.res_partner_1") asume que ese dato demo existe en la base de datos de test. Si otro módulo se instala sin datos demo, o el external ID cambia, el test falla por una razón ajena a lo que pretende validar. Crear los datos propios en setUp() es más verboso pero mucho más fiable.

# Frágil: depende de que ese dato demo exista con ese ID exacto
partner = self.env.ref("base.res_partner_1")

# Fiable: el test controla exactamente los datos que usa
partner = self.env["res.partner"].create({"name": "Cliente Test"})

Cuándo mockear

Mocks solo en el borde del sistema, nunca en el ORM

Mockear una llamada a una API externa (pasarela de pago, servicio de envío de SMS) es correcto: no quieres que tus tests dependan de un tercero. Mockear el propio ORM de Odoo (search, create) para "que el test pase rápido" es una señal de alarma: dejas de probar el comportamiento real y empiezas a probar tus propias suposiciones.

from unittest.mock import patch

class TestNotificacion(TransactionCase):
    @patch("mi_modulo.models.documento.requests.post")
    def test_envio_sms_falla_no_rompe_confirmacion(self, mock_post):
        mock_post.side_effect = ConnectionError("timeout")
        doc = self.env["mi_modulo.documento"].create({"partner_id": self.partner.id})
        doc.action_confirm()  # no debe lanzar aunque el SMS falle
        self.assertEqual(doc.state, "confirmed")
SituaciónQué hacer
Llamada a API externa (pago, SMS, email)Mock del cliente HTTP, nunca del ORM
Datos necesarios para el testCrearlos en setUp(), no asumir demo
Referencia a dato garantizado por tu propio móduloenv.ref() es válido
Verificar reglas de accesowith_user() + assertRaises(AccessError)

Resumen

TransactionCase te da aislamiento gratis; aúnalo con datos creados explícitamente en cada test y mocks reservados al borde del sistema. Un test que depende de datos demo ajenos o que mockea el ORM no te protege de nada: solo aparenta cobertura.

en Odoo
IA aplicada al desarrollo Odoo
Agentes, MCP, generación de specs y revisión de código (experiencia propia)