2 Commits

4 changed files with 83 additions and 1 deletions

View File

@@ -159,7 +159,44 @@ Nota: El volumen monta `tienda_ilusion/` en `/app/`, por lo que el path correcto
## Tests ## Tests
- Framework: Django unittest - Framework: Django unittest
- Directorio: don_confiao/tests/ - Directorio: don_confiao/tests/
- Ejecutar: `docker-compose -f docker-compose.dev.yml run --rm django python manage.py test` - Ejecutar: `docker compose -f docker-compose.dev.yml run --rm django python manage.py test`
## Workflow TDD (Semáforo Rojo/Verde)
Todo cambio o nueva funcionalidad debe seguir TDD. **Está prohibido asumir fallos de tests: todo fallo debe ser confirmado ejecutando los tests.**
### Regla de oro: confirmar antes de modificar
Antes de modificar tests (por cambios en comportamiento o por nuevas funcionalidades), **SIEMPRE ejecutar los tests primero** y confirmar que el fallo esperado realmente ocurre. Nunca asumir que un test falla: verificar el fallo con la ejecución real.
### Ciclo Rojo → Verde → Refactor
1. **ROJO (escribir el test y confirmar que falla)**:
- Escribir o modificar el test que describe el comportamiento esperado.
- Ejecutar los tests **antes de tocar el código de producción**.
- Confirmar que el test falla por el motivo esperado (assertion fallida por el comportamiento nuevo, no por error de setup o de importación).
- Copiar el output del fallo como evidencia del semáforo rojo.
2. **VERDE (implementar lo mínimo para que pase)**:
- Implementar el código de producción mínimo necesario para que el test pase.
- Volver a ejecutar los tests y confirmar que el semáforo queda en verde.
3. **REFACTOR (limpiar con los tests en verde)**:
- Refactorizar y limpiar el código sin cambiar comportamiento.
- Re-ejecutar los tests para confirmar que siguen en verde.
### Ejecutar tests
Siempre ejecutar dentro del contenedor de desarrollo:
```bash
# Test específico (durante el ciclo, preferible sobre el suite completo para ser rápido)
docker compose -f docker-compose.dev.yml run --rm django python manage.py test don_confiao.tests.<archivo>
# Suite completa (al finalizar, para confirmar que nada se rompió)
docker compose -f docker-compose.dev.yml run --rm django python manage.py test
```
### Confirmar el fallo, no asumirlo
- Si un test falla o se espera que falle, **ejecutarlo y mostrar el resultado** antes de cambiar cualquier código o test.
- Verificar que el fallo corresponde a la razón esperada (leer el traceback), no a un problema de entorno, migraciones, importaciones o fixtures.
- No modificar tests para "hacerlos pasar" si el fallo no fue previamente confirmado.
## Comandos Útiles (dentro del contenedor) ## Comandos Útiles (dentro del contenedor)
- Migraciones: `docker-compose -f docker-compose.dev.yml run --rm django python manage.py makemigrations && docker-compose -f docker-compose.dev.yml run --rm django python manage.py migrate` - Migraciones: `docker-compose -f docker-compose.dev.yml run --rm django python manage.py makemigrations && docker-compose -f docker-compose.dev.yml run --rm django python manage.py migrate`

View File

@@ -0,0 +1,14 @@
# Generated by Django 5.0.6 on 2026-08-10 03:51
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('don_confiao', '0050_catalogsale_code_sale_code'),
('don_confiao', '0051_storesettings_logo'),
]
operations = [
]

View File

@@ -36,6 +36,7 @@ class SaleSerializer(serializers.ModelSerializer):
model = Sale model = Sale
fields = [ fields = [
"id", "id",
"code",
"customer", "customer",
"date", "date",
"saleline_set", "saleline_set",
@@ -68,6 +69,7 @@ class CatalogSaleSerializer(serializers.ModelSerializer):
model = CatalogSale model = CatalogSale
fields = [ fields = [
"id", "id",
"code",
"customer", "customer",
"date", "date",
"catalogsaleline_set", "catalogsaleline_set",

View File

@@ -8,6 +8,7 @@ from ..admin import CatalogSaleAdmin, SaleAdmin
from ..models.customers import Customer from ..models.customers import Customer
from ..models.products import Product from ..models.products import Product
from ..models.sales import CatalogSale, Sale from ..models.sales import CatalogSale, Sale
from ..serializers import CatalogSaleSerializer, SaleSerializer
from .Mixins import LoginMixin from .Mixins import LoginMixin
@@ -191,3 +192,31 @@ class TestOrderSummaryPublic(APITestCase, LoginMixin):
def test_admin_list_display_includes_code(self): def test_admin_list_display_includes_code(self):
self.assertIn("code", SaleAdmin.list_display) self.assertIn("code", SaleAdmin.list_display)
self.assertIn("code", CatalogSaleAdmin.list_display) self.assertIn("code", CatalogSaleAdmin.list_display)
def test_sale_serializer_includes_code(self):
sale = self._create_sale()
data = SaleSerializer(sale).data
self.assertIn("code", data)
self.assertEqual(data["code"], sale.code)
def test_catalog_sale_serializer_includes_code(self):
catalog_sale = self._create_catalog_sale()
data = CatalogSaleSerializer(catalog_sale).data
self.assertIn("code", data)
self.assertEqual(data["code"], catalog_sale.code)
def test_sales_list_endpoint_includes_code(self):
self.login()
sale = self._create_sale()
response = self.client.get("/don_confiao/api/sales/")
self.assertEqual(response.status_code, status.HTTP_200_OK)
item = next(i for i in response.json() if i["id"] == sale.id)
self.assertEqual(item["code"], sale.code)
def test_catalog_sales_list_endpoint_includes_code(self):
self.login()
catalog_sale = self._create_catalog_sale()
response = self.client.get("/don_confiao/api/catalog_sales/")
self.assertEqual(response.status_code, status.HTTP_200_OK)
item = next(i for i in response.json() if i["id"] == catalog_sale.id)
self.assertEqual(item["code"], catalog_sale.code)