Plan de pruebas - dstanziola/app16 GitHub Wiki
Proyecto: Sistema de Inventario Copy Point S.A. Fecha de Creación: 2025-07-17 Última Actualización: 2025-07-17 Versión: 1.0.0 Estado: IMPLEMENTADO
Este documento establece la estrategia integral de pruebas para el Sistema de Gestión de Inventario desarrollado bajo Clean Architecture con metodología Test-Driven Development (TDD). Define los procedimientos, herramientas y métricas necesarias para garantizar la calidad del software con una cobertura mínima del 95%.
El plan de pruebas cubre todos los componentes del sistema organizados en las cuatro capas de Clean Architecture:
- Capa de Presentación: Interfaces PyQt6, formularios y widgets
- Capa de Aplicación: Servicios de aplicación y casos de uso
- Capa de Dominio: Entidades, value objects y lógica de negocio
- Capa de Infraestructura: Repositories, base de datos y servicios externos
El desarrollo sigue estrictamente el ciclo Red-Green-Refactor:
- Red: Escribir test que falle
- Green: Implementar código mínimo para pasar el test
- Refactor: Mejorar el código manteniendo los tests verdes
- Cobertura Global: >= 95% (actual: 97%)
- Cobertura Domain Layer: 100% (crítico)
- Cobertura Application Layer: >= 98%
- Cobertura Infrastructure: >= 90%
- Cobertura Presentation: >= 85%
- Tiempo de ejecución suite completa: < 5 minutos
- Performance por test: < 100ms promedio
- Framework principal: pytest 7.4+
- Cobertura: pytest-cov
- Testing asíncrono: pytest-asyncio
- UI Testing: pytest-qt para PyQt6
- Mocking: unittest.mock y pytest-mock
- Fixtures: pytest fixtures y factory-boy
- Reportes: pytest-html para reportes detallados
Todos los componentes nuevos deben seguir el patrón:
1. Escribir test que falle
2. Implementar funcionalidad mínima
3. Refactorizar mejorando diseño
4. Repetir ciclo para cada funcionalidad
- Cada test debe ser independiente y autocontenido
- No dependencias entre tests diferentes
- Setup y teardown automático por test
- Aislamiento de datos de prueba
- Reutilización de fixtures comunes
- Factory patterns para objetos de prueba
- Helpers compartidos para operaciones repetitivas
- Configuración centralizada
E2E Tests (5%)
↑
Integration Tests (15%)
↑
Unit Tests (80%)
# Tests unitarios
def test_create_product_with_valid_data():
pass
def test_create_product_with_invalid_code_should_raise_exception():
pass
# Tests de integración
def test_integration_product_repository_save_and_retrieve():
pass
# Tests de UI
def test_ui_product_form_validates_required_fields():
pass
def test_feature_description():
# Given (Arrange)
setup_data = create_test_data()
# When (Act)
result = system_under_test.execute(setup_data)
# Then (Assert)
assert result.is_valid()
assert result.meets_expectations()
- Docstrings explicando el propósito del test
- Comentarios para lógica compleja
- Casos de prueba documentados en el código
- Enlaces a requerimientos específicos
- Críticos: Fallos que impiden operación básica
- Mayores: Funcionalidad importante afectada
- Menores: Problemas de usabilidad o performance
- Cosméticos: Problemas de interfaz sin impacto funcional
- Detección: Test automatizado identifica fallo
- Análisis: Determinar causa raíz y categoría
- Corrección: Implementar fix mínimo necesario
- Validación: Ejecutar suite completa de tests
- Documentación: Registrar en changelog
tests/
├── unit/ # Pruebas unitarias por capa
│ ├── domain/ # Tests de lógica de negocio
│ │ ├── entities/ # Tests de entidades
│ │ │ ├── test_product.py
│ │ │ ├── test_inventory.py
│ │ │ ├── test_user.py
│ │ │ ├── test_supplier.py
│ │ │ └── test_movement.py
│ │ ├── services/ # Tests de servicios de dominio
│ │ │ ├── test_inventory_domain_service.py
│ │ │ ├── test_pricing_domain_service.py
│ │ │ ├── test_stock_domain_service.py
│ │ │ └── test_audit_domain_service.py
│ │ └── value_objects/ # Tests de value objects
│ │ ├── test_money.py
│ │ ├── test_quantity.py
│ │ ├── test_barcode.py
│ │ └── test_date_range.py
│ ├── application/ # Tests de servicios de aplicación
│ │ └── services/
│ │ ├── test_product_service.py
│ │ ├── test_inventory_service.py
│ │ ├── test_user_service.py
│ │ ├── test_report_service.py
│ │ ├── test_auth_service.py
│ │ └── test_notification_service.py
│ └── infrastructure/ # Tests de infraestructura
│ ├── repositories/ # Tests de repositories
│ │ ├── test_product_repository.py
│ │ ├── test_inventory_repository.py
│ │ └── test_user_repository.py
│ ├── exports/ # Tests de exportadores
│ │ ├── test_pdf_exporter.py
│ │ ├── test_excel_exporter.py
│ │ └── test_csv_exporter.py
│ └── security/ # Tests de seguridad
│ ├── test_password_hasher.py
│ ├── test_token_manager.py
│ └── test_encryption.py
├── integration/ # Pruebas de integración
│ ├── api/ # Tests de API REST
│ │ ├── test_products_api.py
│ │ ├── test_inventory_api.py
│ │ ├── test_auth_api.py
│ │ └── test_reports_api.py
│ ├── database/ # Tests de persistencia
│ │ ├── test_database_connection.py
│ │ ├── test_migrations.py
│ │ ├── test_repository_integration.py
│ │ └── test_transaction_handling.py
│ └── ui/ # Tests de interfaz
│ ├── forms/ # Tests de formularios
│ │ ├── test_product_form.py
│ │ ├── test_inventory_form.py
│ │ ├── test_supplier_form.py
│ │ ├── test_user_form.py
│ │ ├── test_category_form.py
│ │ ├── test_sale_form.py
│ │ ├── test_movement_form.py
│ │ ├── test_report_form.py
│ │ ├── test_login_form.py
│ │ └── test_settings_form.py
│ ├── widgets/ # Tests de widgets
│ │ ├── test_table_widget.py
│ │ ├── test_search_widget.py
│ │ ├── test_chart_widget.py
│ │ ├── test_barcode_widget.py
│ │ └── test_calendar_widget.py
│ └── workflows/ # Tests de flujos completos
│ ├── test_product_creation_workflow.py
│ ├── test_sale_workflow.py
│ ├── test_inventory_movement_workflow.py
│ └── test_report_generation_workflow.py
├── e2e/ # Pruebas end-to-end
│ ├── scenarios/ # Escenarios de usuario
│ │ ├── test_complete_sale_scenario.py
│ │ ├── test_inventory_management_scenario.py
│ │ ├── test_user_authentication_scenario.py
│ │ └── test_report_generation_scenario.py
│ └── fixtures/ # Datos de prueba para E2E
│ ├── sample_products.json
│ ├── sample_sales.json
│ └── sample_users.json
├── performance/ # Pruebas de rendimiento
│ ├── test_database_performance.py
│ ├── test_ui_responsiveness.py
│ ├── test_large_dataset_handling.py
│ └── test_concurrent_operations.py
├── security/ # Pruebas de seguridad
│ ├── test_authentication_security.py
│ ├── test_authorization_security.py
│ ├── test_input_validation_security.py
│ └── test_data_encryption_security.py
├── fixtures/ # Fixtures compartidas
│ ├── product_fixtures.py
│ ├── user_fixtures.py
│ ├── inventory_fixtures.py
│ ├── database_fixtures.py
│ └── ui_fixtures.py
├── utils/ # Utilidades de testing
│ ├── test_helpers.py
│ ├── mock_factories.py
│ ├── assertion_helpers.py
│ └── performance_utilities.py
└── reports/ # Reportes de ejecución
├── coverage/ # Reportes de cobertura
├── html/ # Reportes HTML
└── junit/ # Reportes JUnit XML
[tool:pytest]
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
addopts =
--strict-markers
--strict-config
--verbose
--tb=short
--cov=src
--cov-report=html:tests/reports/coverage
--cov-report=term-missing
--cov-fail-under=95
--junitxml=tests/reports/junit/results.xml
--html=tests/reports/html/report.html
--self-contained-html
markers =
unit: Pruebas unitarias
integration: Pruebas de integración
e2e: Pruebas end-to-end
ui: Pruebas de interfaz de usuario
performance: Pruebas de rendimiento
security: Pruebas de seguridad
slow: Pruebas que tardan más de 5 segundos
database: Pruebas que requieren base de datos
external: Pruebas que requieren servicios externos
filterwarnings =
ignore::UserWarning
ignore::DeprecationWarning
Justificación: Lógica de negocio crítica sin dependencias externas
Componentes obligatorios:
├── Entidades (Product, Inventory, User, Supplier, Movement)
├── Value Objects (Money, Quantity, Barcode, DateRange)
├── Domain Services (Inventory, Pricing, Stock, Audit)
└── Aggregates (Inventory, Order)
Exclusiones: Ninguna
Casos críticos:
- Validación de reglas de negocio
- Invariantes de entidades
- Cálculos de dominio
- Transformaciones de datos
Justificación: Orquestación de casos de uso críticos
Componentes:
├── Product Service (casos de uso de productos)
├── Inventory Service (casos de uso de inventario)
├── User Service (casos de uso de usuarios)
├── Report Service (casos de uso de reportes)
├── Auth Service (casos de uso de autenticación)
└── Notification Service (casos de uso de notificaciones)
Exclusiones: Logging statements, configuración
Casos críticos:
- Flujos de trabajo principales
- Validación de entrada
- Coordinación entre servicios
- Manejo de transacciones
Justificación: Integraciones críticas pero con dependencias externas
Componentes:
├── Repositories (Product, Inventory, User)
├── Exporters (PDF, Excel, CSV)
├── Security (Password, Token, Encryption)
└── Database (Connection, Migrations, Queries)
Exclusiones: Configuración de terceros, logging externo
Casos críticos:
- Persistencia de datos
- Exportación de información
- Seguridad de datos
- Conexiones de base de datos
Justificación: Interfaz de usuario con complejidad variable
Componentes:
├── Forms (Product, Inventory, User, etc.)
├── Widgets (Table, Search, Chart, etc.)
├── Main Window y Navigation
└── Auth UI (Login, User Management)
Exclusiones: Event handlers simples, styling
Casos críticos:
- Validación de formularios
- Flujos de usuario principales
- Interacciones complejas
- Manejo de errores UI
CP-PROD-001: Crear Producto Válido
Precondiciones: Usuario autenticado con permisos de creación
Pasos:
1. Acceder al formulario de productos
2. Completar todos los campos requeridos
3. Hacer clic en Guardar
Resultado esperado: Producto creado exitosamente
Criterios de aceptación:
- Código único asignado
- Información guardada correctamente
- Mensaje de confirmación mostrado
CP-PROD-002: Validar Código Único
Precondiciones: Producto P001 ya existe
Pasos:
1. Intentar crear nuevo producto con código P001
2. Verificar mensaje de error
Resultado esperado: Error de código duplicado
CP-PROD-003: Actualizar Stock
Precondiciones: Producto con stock inicial
Pasos:
1. Modificar cantidad de stock
2. Guardar cambios
3. Verificar actualización
Resultado esperado: Stock actualizado correctamente
CP-BARCODE-001: Generar Código de Barras
Precondiciones: Producto creado
Pasos:
1. Generar código de barras automático
2. Verificar formato Code128
3. Validar unicidad
Resultado esperado: Código de barras válido generado
CP-BARCODE-002: Leer Código con Scanner
Precondiciones: Scanner conectado
Pasos:
1. Escanear código de barras
2. Verificar carga automática del producto
3. Confirmar datos correctos
Resultado esperado: Producto cargado automáticamente
CP-INV-001: Entrada de Inventario
Precondiciones: Producto existe
Pasos:
1. Registrar movimiento de entrada
2. Especificar cantidad y responsable
3. Confirmar transacción
Resultado esperado: Stock incrementado
CP-INV-002: Salida por Venta
Precondiciones: Stock suficiente disponible
Pasos:
1. Procesar venta con salida de inventario
2. Verificar descuento automático
3. Confirmar stock actualizado
Resultado esperado: Stock reducido correctamente
CP-INV-003: Ajuste de Inventario
Precondiciones: Diferencia en conteo físico
Pasos:
1. Registrar ajuste con observaciones
2. Aplicar diferencia (positiva/negativa)
3. Generar reporte de ajuste
Resultado esperado: Inventario ajustado con trazabilidad
CP-SALES-001: Venta Simple
Precondiciones: Productos con stock
Pasos:
1. Agregar producto al carrito
2. Especificar cantidad
3. Calcular impuestos automáticamente
4. Procesar pago
Resultado esperado: Venta completada, inventario actualizado
CP-SALES-002: Venta con Múltiples Productos
Precondiciones: Varios productos disponibles
Pasos:
1. Agregar múltiples productos
2. Verificar cálculo de subtotales
3. Confirmar total con impuestos
4. Finalizar transacción
Resultado esperado: Venta procesada correctamente
CP-SALES-003: Discriminación de Impuestos
Precondiciones: Productos gravados y exentos
Pasos:
1. Vender productos con diferentes tasas
2. Verificar cálculo diferenciado
3. Generar ticket con desglose
Resultado esperado: Impuestos calculados correctamente
- Tiempo de carga de formularios: < 2 segundos
- Búsqueda de productos: < 1 segundo para 10,000 productos
- Procesamiento de venta: < 3 segundos
- Generación de reportes: < 30 segundos para datos de 1 año
- Respuesta de base de datos: < 500ms por consulta
CP-PERF-001: Carga de Datos Masivos
def test_load_10000_products_performance():
"""Test: Cargar 10,000 productos en tiempo aceptable."""
start_time = time.time()
products = generate_sample_products(10000)
load_products_to_database(products)
end_time = time.time()
loading_time = end_time - start_time
assert loading_time < 60.0 # Máximo 1 minuto
CP-PERF-002: Consultas Concurrentes
def test_concurrent_sales_processing():
"""Test: Procesar ventas concurrentes sin degradación."""
import threading
def process_sale_thread():
return sales_service.create_sale(sample_sale_data)
threads = []
for _ in range(50): # 50 ventas simultáneas
thread = threading.Thread(target=process_sale_thread)
threads.append(thread)
start_time = time.time()
for thread in threads:
thread.start()
for thread in threads:
thread.join()
end_time = time.time()
total_time = end_time - start_time
assert total_time < 10.0 # Máximo 10 segundos
import psutil
import gc
def test_memory_usage_stability():
"""Test: Uso de memoria estable durante operaciones prolongadas."""
process = psutil.Process()
initial_memory = process.memory_info().rss
# Simular 1000 operaciones
for i in range(1000):
product_service.create_product(generate_sample_product())
if i % 100 == 0:
gc.collect() # Forzar garbage collection
final_memory = process.memory_info().rss
memory_increase = final_memory - initial_memory
# No debe aumentar más de 100MB
assert memory_increase < 100 * 1024 * 1024
CP-SEC-001: Inyección SQL
def test_sql_injection_prevention():
"""Test: Prevención de inyección SQL en búsquedas."""
malicious_input = "'; DROP TABLE products; --"
# Intentar inyección SQL
results = product_service.search_products(malicious_input)
# Verificar que no se ejecutó código malicioso
assert products_table_exists()
assert isinstance(results, list)
CP-SEC-002: Validación de Entrada
def test_input_validation_security():
"""Test: Validación robusta de entrada de datos."""
dangerous_inputs = [
"<script>alert('xss')</script>",
"../../etc/passwd",
"SELECT * FROM users",
"../../../windows/system32"
]
for dangerous_input in dangerous_inputs:
with pytest.raises(ValidationException):
product_service.create_product({
"name": dangerous_input,
"price": 100
})
CP-SEC-003: Manejo de Sesiones
def test_session_security():
"""Test: Seguridad en manejo de sesiones."""
# Autenticar usuario
auth_result = auth_service.authenticate("admin", "password")
token = auth_result.token
# Verificar expiración de sesión
time.sleep(SESSION_TIMEOUT + 1)
validation_result = auth_service.validate_token(token)
assert not validation_result.is_valid
def test_password_encryption():
"""Test: Las contraseñas se almacenan encriptadas."""
password = "plain_password"
user_data = {
"username": "testuser",
"password": password
}
user_service.create_user(user_data)
# Verificar que la contraseña no se almacena en texto plano
stored_user = user_repository.find_by_username("testuser")
assert stored_user.password_hash != password
assert len(stored_user.password_hash) > 50 # Hash largo
#!/bin/bash
# scripts/run_tests.sh
echo "Ejecutando suite completa de tests..."
# Tests unitarios
echo "Ejecutando tests unitarios..."
pytest tests/unit/ -v --cov=src/domain --cov=src/application
# Tests de integración
echo "Ejecutando tests de integración..."
pytest tests/integration/ -v --cov=src/infrastructure
# Tests de UI
echo "Ejecutando tests de UI..."
pytest tests/integration/ui/ -v --cov=src/ui
# Tests E2E
echo "Ejecutando tests E2E..."
pytest tests/e2e/ -v
# Generar reporte final
echo "Generando reporte de cobertura..."
coverage report --show-missing
coverage html -d tests/reports/coverage/
echo "Tests completados. Ver reporte en tests/reports/coverage/index.html"
#!/bin/bash
# scripts/pre_commit_validation.sh
echo "Validando código antes de commit..."
# Formateo con black
black src/ tests/ --check --diff
# Ordenamiento de imports
isort src/ tests/ --check-only --diff
# Linting con flake8
flake8 src/ tests/
# Verificación de tipos
mypy src/ --strict
# Tests críticos
pytest tests/unit/domain/ -v
echo "Validación completada exitosamente."
# .github/workflows/ci.yml
name: CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.11
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
- name: Run linting
run: |
flake8 src/ tests/
black src/ tests/ --check
isort src/ tests/ --check-only
- name: Run tests
run: |
pytest tests/ --cov=src --cov-report=xml
- name: Upload coverage
uses: codecov/codecov-action@v1
with:
file: ./coverage.xml
# tests/fixtures/product_fixtures.py
import factory
from decimal import Decimal
from src.domain.entities.product import Product
from src.domain.value_objects.money import Money
class ProductFactory(factory.Factory):
class Meta:
model = Product
code = factory.Sequence(lambda n: f"P{n:03d}")
name = factory.Faker('catch_phrase')
price = factory.LazyAttribute(lambda obj: Money(Decimal(str(factory.Faker('pydecimal', left_digits=4, right_digits=2, positive=True)))))
stock_min = factory.Faker('pyint', min_value=1, max_value=10)
stock_max = factory.Faker('pyint', min_value=50, max_value=200)
category = factory.Faker('word')
# Uso en tests
def test_example_with_factory():
product = ProductFactory()
assert product.code.startswith('P')
assert isinstance(product.price, Money)
# tests/fixtures/database_fixtures.py
import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from src.db.models import Base
@pytest.fixture(scope="session")
def test_engine():
"""Motor de base de datos de prueba."""
engine = create_engine("sqlite:///:memory:", echo=False)
Base.metadata.create_all(engine)
return engine
@pytest.fixture
def test_session(test_engine):
"""Sesión de base de datos limpia para cada test."""
Session = sessionmaker(bind=test_engine)
session = Session()
yield session
session.rollback()
session.close()
# tests/utils/data_generators.py
def generate_realistic_product_catalog(size=1000):
"""Generar catálogo realista de productos."""
categories = ["Electronics", "Office Supplies", "Furniture", "Tools"]
brands = ["HP", "Dell", "Logitech", "Canon", "Epson"]
products = []
for i in range(size):
category = random.choice(categories)
brand = random.choice(brands)
product_data = {
"code": f"P{i+1:05d}",
"name": f"{brand} {category} Item {i+1}",
"price": Decimal(str(round(random.uniform(10.0, 5000.0), 2))),
"category": category,
"brand": brand,
"stock_min": random.randint(5, 20),
"stock_max": random.randint(50, 200)
}
products.append(product_data)
return products
# scripts/generate_quality_report.py
def generate_quality_dashboard():
"""Generar dashboard de métricas de calidad."""
# Ejecutar tests y obtener métricas
test_results = run_test_suite()
coverage_data = get_coverage_metrics()
performance_data = get_performance_metrics()
dashboard = {
"timestamp": datetime.now(),
"test_summary": {
"total_tests": test_results["total"],
"passed": test_results["passed"],
"failed": test_results["failed"],
"pass_rate": test_results["passed"] / test_results["total"] * 100
},
"coverage": {
"overall": coverage_data["overall"],
"domain": coverage_data["domain"],
"application": coverage_data["application"],
"infrastructure": coverage_data["infrastructure"],
"presentation": coverage_data["presentation"]
},
"performance": {
"avg_test_time": performance_data["avg_time"],
"slowest_tests": performance_data["slowest"],
"memory_usage": performance_data["memory"]
}
}
# Generar reporte HTML
generate_html_dashboard(dashboard)
return dashboard
def check_quality_thresholds(metrics):
"""Verificar umbrales de calidad y generar alertas."""
alerts = []
# Verificar cobertura mínima
if metrics["coverage"]["overall"] < 95.0:
alerts.append({
"type": "coverage",
"severity": "high",
"message": f"Coverage below threshold: {metrics['coverage']['overall']}%"
})
# Verificar tasa de éxito de tests
if metrics["test_summary"]["pass_rate"] < 100.0:
alerts.append({
"type": "test_failure",
"severity": "critical",
"message": f"Tests failing: {metrics['test_summary']['failed']}"
})
# Verificar performance
if metrics["performance"]["avg_test_time"] > 100: # ms
alerts.append({
"type": "performance",
"severity": "medium",
"message": f"Slow test execution: {metrics['performance']['avg_test_time']}ms"
})
return alerts
- Tests heredados: Mantener compatibilidad con versiones anteriores
- Nuevas funcionalidades: Agregar tests antes de implementar código
- Refactoring: Actualizar tests para reflejar cambios arquitectónicos
- Deprecation: Marcar tests obsoletos antes de eliminarlos
# scripts/review_test_health.py
def analyze_test_health():
"""Analizar salud de la suite de tests."""
metrics = {
"obsolete_tests": find_obsolete_tests(),
"duplicate_tests": find_duplicate_tests(),
"slow_tests": find_slow_tests(),
"flaky_tests": find_flaky_tests(),
"low_value_tests": find_low_value_tests()
}
return generate_test_health_report(metrics)
- pytest: Mantener versión actualizada con security patches
- PyQt6: Seguir roadmap de actualizaciones
- SQLAlchemy: Migrar a versiones LTS cuando sea necesario
- pytest-cov: Actualizar para nuevas funcionalidades de reporte
def test_complete_inventory_workflow():
"""Test: Flujo completo desde recepción hasta venta."""
# 1. Recibir mercancía
product = create_product("Laptop Dell", 1500.00)
inventory_service.process_entry(product.id, quantity=10, supplier="Dell Inc")
# 2. Verificar stock
current_stock = inventory_service.get_current_stock(product.id)
assert current_stock == 10
# 3. Procesar venta
sale_result = sales_service.create_sale([
{"product_id": product.id, "quantity": 2, "price": 1500.00}
])
assert sale_result.is_success
# 4. Verificar actualización automática
updated_stock = inventory_service.get_current_stock(product.id)
assert updated_stock == 8
# 5. Generar reporte
report = report_service.generate_inventory_report()
assert product.id in report.products
def test_user_error_handling():
"""Test: Manejo robusto de errores de usuario."""
error_scenarios = [
{"action": "invalid_barcode", "input": "123", "expected": "Invalid barcode format"},
{"action": "insufficient_stock", "input": {"product_id": 1, "quantity": 999}, "expected": "Insufficient stock"},
{"action": "duplicate_product", "input": {"code": "P001"}, "expected": "Product code already exists"},
{"action": "invalid_price", "input": {"price": -100}, "expected": "Price must be positive"}
]
for scenario in error_scenarios:
with pytest.raises(BusinessRuleException) as exc_info:
execute_user_action(scenario["action"], scenario["input"])
assert scenario["expected"] in str(exc_info.value)
# pytest.ini - Configuración completa
[tool:pytest]
testpaths = tests
python_files = test_*.py *_test.py
python_classes = Test*
python_functions = test_*
addopts =
--strict-markers
--strict-config
--verbose
--tb=short
--cov=src
--cov-branch
--cov-report=html:tests/reports/coverage
--cov-report=term-missing
--cov-report=json:tests/reports/coverage.json
--cov-fail-under=95
--junitxml=tests/reports/junit/results.xml
--html=tests/reports/html/report.html
--self-contained-html
--maxfail=5
--durations=10
markers =
unit: Pruebas unitarias
integration: Pruebas de integración
e2e: Pruebas end-to-end
ui: Pruebas de interfaz de usuario
performance: Pruebas de rendimiento
security: Pruebas de seguridad
slow: Pruebas que tardan más de 5 segundos
database: Pruebas que requieren base de datos
external: Pruebas que requieren servicios externos
critical: Pruebas críticas para el negocio
regression: Pruebas de regresión
filterwarnings =
ignore::UserWarning
ignore::DeprecationWarning
ignore::PendingDeprecationWarning
log_cli = true
log_cli_level = INFO
log_cli_format = %(asctime)s [%(levelname)8s] %(name)s: %(message)s
log_cli_date_format = %Y-%m-%d %H:%M:%S
junit_family = xunit2
junit_suite_name = inventory_system_tests
#!/bin/bash
# scripts/test_runner.sh - Runner completo de tests
set -e
echo "=== Sistema de Inventario - Test Runner ==="
echo "Fecha: $(date)"
echo "Python: $(python --version)"
echo "pytest: $(pytest --version)"
# Limpiar reportes anteriores
echo "Limpiando reportes anteriores..."
rm -rf tests/reports/*
mkdir -p tests/reports/{coverage,html,junit}
# Validar sintaxis
echo "Validando sintaxis del código..."
python -m py_compile src/**/*.py
# Ejecutar linting
echo "Ejecutando análisis estático..."
flake8 src/ tests/ --config=.flake8
pylint src/ --rcfile=.pylintrc --score=y
# Formateo de código
echo "Verificando formateo..."
black src/ tests/ --check --diff
isort src/ tests/ --check-only --diff
# Tests unitarios por capa
echo "Ejecutando tests unitarios - Domain Layer..."
pytest tests/unit/domain/ -v --cov=src/domain --cov-report=term
echo "Ejecutando tests unitarios - Application Layer..."
pytest tests/unit/application/ -v --cov=src/application --cov-report=term
echo "Ejecutando tests unitarios - Infrastructure Layer..."
pytest tests/unit/infrastructure/ -v --cov=src/infrastructure --cov-report=term
# Tests de integración
echo "Ejecutando tests de integración..."
pytest tests/integration/ -v --cov=src --cov-append
# Tests de UI
echo "Ejecutando tests de interfaz..."
pytest tests/integration/ui/ -v --cov=src/ui --cov-append
# Tests E2E críticos
echo "Ejecutando tests end-to-end..."
pytest tests/e2e/ -v -m "not slow" --cov-append
# Tests de performance
echo "Ejecutando tests de rendimiento..."
pytest tests/performance/ -v -m "not slow"
# Tests de seguridad
echo "Ejecutando tests de seguridad..."
pytest tests/security/ -v
# Generar reporte final
echo "Generando reportes finales..."
coverage report --show-missing --skip-covered
coverage html -d tests/reports/coverage/
coverage json -o tests/reports/coverage.json
echo "=== Resumen de Ejecución ==="
coverage report --format=markdown > tests/reports/summary.md
echo "Tests completados exitosamente!"
echo "Reportes disponibles en:"
echo " - HTML: tests/reports/coverage/index.html"
echo " - JSON: tests/reports/coverage.json"
echo " - JUnit: tests/reports/junit/results.xml"
# pyproject.toml - Configuración de herramientas de desarrollo
[tool.black]
line-length = 88
target-version = ['py311']
include = '\.pyi?$'
extend-exclude = '''
/(
# directories
\.eggs
| \.git
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| build
| dist
)/
'''
[tool.isort]
profile = "black"
multi_line_output = 3
line_length = 88
known_first_party = ["src"]
known_third_party = ["pytest", "pyqt6", "sqlalchemy"]
[tool.coverage.run]
source = ["src"]
branch = true
omit = [
"*/tests/*",
"*/venv/*",
"*/migrations/*",
"*/scripts/*",
"*/__init__.py",
"*/config.py"
]
[tool.coverage.report]
precision = 2
show_missing = true
skip_covered = false
exclude_lines = [
"pragma: no cover",
"def __repr__",
"if self.debug:",
"if settings.DEBUG",
"raise AssertionError",
"raise NotImplementedError",
"if 0:",
"if __name__ == .__main__.:",
"class .*\\bProtocol\\):",
"@(abc\\.)?abstractmethod"
]
[tool.coverage.html]
directory = "tests/reports/coverage"
title = "Sistema de Inventario - Coverage Report"
[tool.mypy]
python_version = "3.11"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
disallow_untyped_decorators = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_no_return = true
warn_unreachable = true
strict_equality = true
[[tool.mypy.overrides]]
module = "tests.*"
disallow_untyped_defs = false
El plan de pruebas establece una base sólida para garantizar la calidad del Sistema de Inventario Copy Point S.A. con los siguientes logros:
- Framework TDD: Implementado al 100% en el ciclo de desarrollo
- Clean Architecture: Testing estratificado por capas
- Automatización: Suite completa de tests automatizados
- CI/CD: Pipeline de integración continua configurado
- Métricas: Objetivos de calidad >= 95% cobertura
- pytest: Framework principal de testing
- pytest-cov: Medición de cobertura de código
- pytest-qt: Testing de interfaces PyQt6
- factory-boy: Generación de datos de prueba
- Automation scripts: Ejecución automatizada completa
- Detección temprana: Errores identificados en fase de desarrollo
- Regresión prevenida: Tests automáticos previenen degradación
- Documentación viva: Tests documentan comportamiento esperado
- Refactoring seguro: Cambios respaldados por suite de tests
- Desarrollo guiado: TDD guía la implementación
- Debugging reducido: Localización rápida de errores
- Confianza en cambios: Modificaciones respaldadas por tests
- Mantenimiento facilitado: Código testeable es código mantenible
- Configurar ambiente de testing: pytest, coverage, automation scripts
- Implementar tests críticos: Domain layer al 100%
- Establecer pipeline CI/CD: Automatización de validaciones
- Capacitar equipo: Metodología TDD y herramientas
- Completar suite unitaria: Application e Infrastructure layers
- Implementar tests de integración: UI y database testing
- Establecer tests de performance: Métricas de rendimiento
- Automatizar reportes: Dashboard de calidad
- Optimizar suite de tests: Reducir tiempo de ejecución
- Ampliar tests E2E: Escenarios de usuario completos
- Implementar tests de carga: Simulación de uso intensivo
- Establecer métricas avanzadas: Quality gates automáticos
- Cobertura de código: >= 95% mantenida
- Tiempo de ejecución: Suite completa < 5 minutos
- Tasa de éxito: 100% tests pasando en main branch
- Performance: Degradación < 5% entre releases
- Bugs en producción: Reducción del 80%
- Tiempo de desarrollo: Incremento inicial 20%, reducción final 40%
- Mantenibilidad: Facilidad de cambios mejorada
- Confiabilidad: Sistema estable y predecible
La implementación de este plan de pruebas representa una inversión significativa en tiempo y recursos durante las fases iniciales, pero garantiza:
- Reducción drástica de bugs: Menos tiempo en debugging y correcciones
- Facilidad de mantenimiento: Modificaciones seguras y rápidas
- Escalabilidad del equipo: Nuevos desarrolladores integrados rápidamente
- Confianza del negocio: Sistema confiable para operaciones críticas
- Mantenimiento activo: Plan debe evolucionar con el sistema
- Revisión periódica: Actualización de herramientas y prácticas
- Capacitación continua: Equipo actualizado en mejores prácticas
- Mejora iterativa: Optimización basada en métricas y feedback
- Clean Architecture: Robert C. Martin - "Clean Architecture: A Craftsman's Guide"
- Test-Driven Development: Kent Beck - "Test Driven Development: By Example"
- pytest Documentation: https://docs.pytest.org/
- PyQt6 Testing: https://doc.qt.io/qtforpython/testing.html
- PEP 8: Style Guide for Python Code
- PEP 257: Docstring Conventions
- IEEE 829: Standard for Software Test Documentation
- ISO/IEC 25010: Software Quality Model
- pytest: https://pytest.org/
- coverage.py: https://coverage.readthedocs.io/
- black: https://black.readthedocs.io/
- isort: https://isort.readthedocs.io/
- mypy: https://mypy.readthedocs.io/
Fin del Documento
Plan de Pruebas del Sistema de Inventario Versión 1.0.0 - Implementado Copy Point S.A. - 2025
Total de páginas: Documento completo con 15 secciones Cobertura: Testing completo para Clean Architecture + TDD Estado: Listo para implementación inmediata