# TESTING-STRATEGY.md - Trading Platform **Version:** 1.0.0 **Fecha:** 2026-01-30 **Proyecto:** trading-platform --- ## Resumen Ejecutivo Este documento define la estrategia de testing para Trading Platform, cubriendo todos los niveles de la pirámide de testing y consideraciones específicas para sistemas de trading con ML. --- ## Niveles de Testing ### Pirámide de Testing ``` ┌─────────────┐ │ E2E │ 10% │ Tests │ ┌──┴─────────────┴──┐ │ Integration │ 20% │ Tests │ ┌──┴───────────────────┴──┐ │ Unit Tests │ 70% └─────────────────────────┘ ``` | Nivel | Porcentaje | Responsabilidad | |-------|------------|-----------------| | Unit | 70% | Lógica de negocio aislada | | Integration | 20% | Interacción entre módulos | | E2E | 10% | Flujos críticos completos | --- ## 1. Unit Tests ### 1.1 Backend (TypeScript/Express) **Framework:** Jest + ts-jest **Estructura:** ``` apps/backend/src/ ├── modules/ │ ├── auth/ │ │ ├── services/ │ │ │ ├── token.service.ts │ │ │ └── __tests__/ │ │ │ └── token.service.spec.ts │ │ └── ... │ └── ... ``` **Convenciones:** - Archivos: `*.spec.ts` junto al archivo fuente - Naming: `describe('ServiceName')` > `describe('methodName')` > `it('should...')` - Mocks: Usar `jest.mock()` para dependencias externas **Ejemplo:** ```typescript // token.service.spec.ts describe('TokenService', () => { describe('generateAccessToken', () => { it('should return a valid JWT token', () => { const token = tokenService.generateAccessToken(mockUser); expect(token).toMatch(/^eyJ/); }); it('should include user id in payload', () => { const token = tokenService.generateAccessToken(mockUser); const decoded = jwt.decode(token); expect(decoded.sub).toBe(mockUser.id); }); }); }); ``` **Coverage mínimo:** 80% ### 1.2 Frontend (React) **Framework:** Vitest + React Testing Library **Estructura:** ``` apps/frontend/src/ ├── components/ │ ├── Button/ │ │ ├── Button.tsx │ │ └── Button.test.tsx │ └── ... ├── hooks/ │ ├── useAuth.ts │ └── __tests__/ │ └── useAuth.test.ts ``` **Convenciones:** - Archivos: `*.test.tsx` o `*.test.ts` - Testing Library: Preferir queries por rol y accesibilidad - Avoid testing implementation details **Ejemplo:** ```typescript // Button.test.tsx describe('Button', () => { it('should call onClick when clicked', async () => { const handleClick = vi.fn(); render(); await userEvent.click(screen.getByRole('button', { name: /click me/i })); expect(handleClick).toHaveBeenCalledTimes(1); }); }); ``` **Coverage mínimo:** 70% ### 1.3 ML Engine (Python) **Framework:** pytest + pytest-cov **Estructura:** ``` apps/ml-engine/ ├── src/ │ ├── models/ │ │ └── range_predictor.py │ └── ... ├── tests/ │ ├── unit/ │ │ ├── test_range_predictor.py │ │ └── test_feature_engineering.py │ └── ... ``` **Convenciones:** - Archivos: `test_*.py` - Fixtures: Usar `@pytest.fixture` para datos de prueba - Parametrize: Usar `@pytest.mark.parametrize` para múltiples casos **Ejemplo:** ```python # test_range_predictor.py class TestRangePredictor: @pytest.fixture def predictor(self): return RangePredictor(symbol='XAUUSD') def test_predict_returns_valid_range(self, predictor, sample_features): result = predictor.predict(sample_features) assert 'predicted_high' in result assert 'predicted_low' in result assert result['predicted_high'] > result['predicted_low'] @pytest.mark.parametrize('confidence_threshold', [0.5, 0.7, 0.9]) def test_filter_by_confidence(self, predictor, confidence_threshold): # Test filtering logic pass ``` **Coverage mínimo:** 75% --- ## 2. Integration Tests ### 2.1 API Integration Tests **Framework:** Jest + Supertest **Objetivo:** Verificar endpoints con base de datos real (test DB) **Setup:** ```typescript // setup/test-db.ts beforeAll(async () => { await setupTestDatabase(); }); afterAll(async () => { await teardownTestDatabase(); }); beforeEach(async () => { await clearTables(); }); ``` **Ejemplo:** ```typescript // auth.integration.spec.ts describe('Auth API Integration', () => { describe('POST /api/v1/auth/login', () => { it('should return tokens for valid credentials', async () => { // Arrange await createTestUser({ email: 'test@example.com', password: 'Test123!' }); // Act const response = await request(app) .post('/api/v1/auth/login') .send({ email: 'test@example.com', password: 'Test123!' }); // Assert expect(response.status).toBe(200); expect(response.body.data).toHaveProperty('accessToken'); expect(response.body.data).toHaveProperty('refreshToken'); }); }); }); ``` ### 2.2 Database Integration Tests **Objetivo:** Verificar queries, triggers y funciones PL/pgSQL ```typescript // wallet.integration.spec.ts describe('Wallet Transactions', () => { it('should update balance after deposit', async () => { const wallet = await createTestWallet({ balance: 100 }); await db.query( 'SELECT financial.process_transaction($1, $2, $3)', [wallet.id, 'deposit', 50] ); const updated = await getWallet(wallet.id); expect(updated.balance).toBe(150); }); }); ``` ### 2.3 ML Pipeline Integration Tests **Objetivo:** Verificar pipeline completo de predicción ```python # test_prediction_pipeline.py class TestPredictionPipeline: def test_full_prediction_flow(self, db_session, redis_client): # 1. Load features from feature store features = load_features('XAUUSD', '2024-01-01') # 2. Run prediction prediction = run_prediction(features) # 3. Verify stored in database stored = db_session.query(Prediction).filter_by( symbol='XAUUSD' ).first() assert stored is not None assert stored.predicted_high == prediction['high'] ``` --- ## 3. E2E Tests ### 3.1 Framework **Herramienta:** Playwright **Estructura:** ``` e2e/ ├── tests/ │ ├── auth/ │ │ ├── login.spec.ts │ │ └── register.spec.ts │ ├── trading/ │ │ └── place-order.spec.ts │ └── ... ├── fixtures/ │ └── test-data.ts └── playwright.config.ts ``` ### 3.2 Flujos Críticos a Testear | Prioridad | Flujo | Descripción | |-----------|-------|-------------| | P0 | Login/Logout | Autenticación completa | | P0 | Registro + Verificación | Nuevo usuario | | P0 | Depositar fondos | Wallet + Stripe | | P1 | Abrir cuenta inversión | PAMM flow | | P1 | Paper trading | Orden → Posición | | P2 | Completar curso | Education flow | | P2 | 2FA setup | Security flow | ### 3.3 Ejemplo E2E ```typescript // e2e/tests/auth/login.spec.ts import { test, expect } from '@playwright/test'; test.describe('Login Flow', () => { test('user can login with valid credentials', async ({ page }) => { // Navigate await page.goto('/login'); // Fill form await page.getByLabel('Email').fill('test@example.com'); await page.getByLabel('Password').fill('Test123!'); // Submit await page.getByRole('button', { name: /sign in/i }).click(); // Verify redirect to dashboard await expect(page).toHaveURL('/dashboard'); await expect(page.getByText('Welcome back')).toBeVisible(); }); test('shows error for invalid credentials', async ({ page }) => { await page.goto('/login'); await page.getByLabel('Email').fill('wrong@example.com'); await page.getByLabel('Password').fill('wrongpassword'); await page.getByRole('button', { name: /sign in/i }).click(); await expect(page.getByText(/invalid credentials/i)).toBeVisible(); }); }); ``` --- ## 4. Testing Específico para Trading ### 4.1 Backtesting de Modelos ML **Objetivo:** Validar performance de modelos con datos históricos ```python # tests/backtesting/test_model_performance.py class TestModelBacktest: def test_model_accuracy_oos(self): """Test Out-of-Sample accuracy""" # Load 12 months of excluded data oos_data = load_oos_data('2025-01', '2025-12') # Run predictions predictions = model.predict(oos_data.features) # Calculate metrics accuracy = calculate_directional_accuracy( predictions, oos_data.actual ) # Minimum threshold assert accuracy >= 0.55, f"OOS accuracy {accuracy} below threshold" ``` ### 4.2 Paper Trading Tests **Objetivo:** Simular operaciones sin riesgo ```typescript // tests/paper-trading/order-execution.spec.ts describe('Paper Trading Order Execution', () => { it('should execute market order at current price', async () => { const account = await createPaperAccount({ balance: 10000 }); const order = await paperTradingService.placeOrder({ accountId: account.id, symbol: 'XAUUSD', side: 'BUY', type: 'MARKET', quantity: 0.1 }); expect(order.status).toBe('FILLED'); expect(order.filledPrice).toBeCloseTo(currentPrice, 2); }); }); ``` ### 4.3 Risk Management Tests ```typescript // tests/risk/position-limits.spec.ts describe('Position Limits', () => { it('should reject order exceeding max position size', async () => { const result = await riskService.validateOrder({ userId: testUser.id, symbol: 'XAUUSD', quantity: 100 // Exceeds limit }); expect(result.allowed).toBe(false); expect(result.reason).toContain('position limit'); }); }); ``` --- ## 5. Mocking Strategies ### 5.1 External Services | Servicio | Estrategia | |----------|------------| | Stripe | Mock SDK responses | | Binance API | Recorded fixtures | | Redis | Redis-mock o real | | LLM (Claude) | Canned responses | ### 5.2 Mock de Stripe ```typescript // __mocks__/stripe.ts export const mockStripe = { customers: { create: jest.fn().mockResolvedValue({ id: 'cus_test123' }), retrieve: jest.fn().mockResolvedValue({ id: 'cus_test123', email: 'test@example.com' }) }, subscriptions: { create: jest.fn().mockResolvedValue({ id: 'sub_test123', status: 'active' }) } }; jest.mock('stripe', () => ({ __esModule: true, default: jest.fn(() => mockStripe) })); ``` ### 5.3 Mock de Market Data ```python # tests/fixtures/market_data.py @pytest.fixture def mock_binance_client(mocker): mock = mocker.patch('binance.Client') mock.return_value.get_klines.return_value = [ [1704067200000, "2050.00", "2055.00", "2048.00", "2052.00", "1000"], [1704067260000, "2052.00", "2058.00", "2051.00", "2056.00", "1200"], ] return mock ``` --- ## 6. CI/CD Integration ### 6.1 GitHub Actions Workflow ```yaml # .github/workflows/test.yml name: Tests on: [push, pull_request] jobs: unit-tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node uses: actions/setup-node@v4 with: node-version: '20' - name: Install dependencies run: npm ci - name: Run unit tests run: npm run test:unit - name: Upload coverage uses: codecov/codecov-action@v3 integration-tests: runs-on: ubuntu-latest services: postgres: image: postgres:16 env: POSTGRES_DB: trading_test POSTGRES_USER: test POSTGRES_PASSWORD: test ports: - 5432:5432 redis: image: redis:7 ports: - 6379:6379 steps: - uses: actions/checkout@v4 - name: Run integration tests run: npm run test:integration e2e-tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Playwright run: npx playwright install --with-deps - name: Run E2E tests run: npm run test:e2e ``` ### 6.2 Pre-commit Hooks ```yaml # .pre-commit-config.yaml repos: - repo: local hooks: - id: test-affected name: Run affected tests entry: npm run test:affected language: system pass_filenames: false ``` --- ## 7. Test Data Management ### 7.1 Factories ```typescript // tests/factories/user.factory.ts export const userFactory = { build: (overrides = {}) => ({ id: faker.string.uuid(), email: faker.internet.email(), passwordHash: bcrypt.hashSync('Test123!', 10), status: 'active', role: 'user', ...overrides }), create: async (overrides = {}) => { const user = userFactory.build(overrides); await db.query('INSERT INTO auth.users ...', [user]); return user; } }; ``` ### 7.2 Fixtures para ML ```python # tests/conftest.py @pytest.fixture(scope='session') def sample_ohlcv_data(): return pd.read_parquet('tests/fixtures/xauusd_sample.parquet') @pytest.fixture(scope='session') def trained_model(): return joblib.load('tests/fixtures/model_v1.joblib') ``` --- ## 8. Comandos de Ejecución ### Backend ```bash # Unit tests npm run test:unit # Integration tests npm run test:integration # Coverage npm run test:coverage ``` ### Frontend ```bash # Unit tests npm run test # Watch mode npm run test:watch # Coverage npm run test:coverage ``` ### ML Engine ```bash # All tests pytest # Unit only pytest tests/unit/ # With coverage pytest --cov=src --cov-report=html ``` ### E2E ```bash # Headless npm run test:e2e # UI mode npm run test:e2e:ui # Specific browser npx playwright test --project=chromium ``` --- ## 9. Métricas y Umbrales | Métrica | Umbral | Medición | |---------|--------|----------| | Unit Test Coverage | ≥ 70% | Codecov | | Integration Test Coverage | ≥ 50% | Codecov | | E2E Critical Paths | 100% pass | Playwright | | ML Model Accuracy (OOS) | ≥ 55% | Custom | | Test Execution Time | < 10 min | CI | --- ## 10. Próximos Pasos 1. **Implementar tests faltantes por módulo** 2. **Configurar CI/CD con GitHub Actions** 3. **Integrar Codecov para tracking de coverage** 4. **Crear fixtures de datos de mercado** 5. **Implementar backtesting automatizado** --- **Última actualización:** 2026-01-30 **Generado por:** Claude Code (Opus 4.5) - Sprint 4