← Назад к вопросам

Как понять что тестировать в оплате?

1.8 Middle🔥 141 комментариев
#Тестирование

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что тестировать в платёжной системе

Оплата - это критическая часть приложения, которая требует наиболее тщательного тестирования. Любая ошибка может привести к потере денег клиентов или потере доходов компании.

Базовые сценарии оплаты

Первый уровень тестирования - проверка основных flow:

describe('Payment Flow', () => {
  // ВАЖНО: Успешная оплата
  it('should complete successful payment', async () => {
    const paymentData = {
      cardNumber: '4242424242424242',
      expiryDate: '12/25',
      cvv: '123',
      amount: 100,
      currency: 'USD',
    };
    
    const result = await processPayment(paymentData);
    
    expect(result.status).toBe('success');
    expect(result.transactionId).toBeDefined();
    expect(result.amount).toBe(100);
  });
  
  // КРИТИЧНО: Отклонённая карта
  it('should handle declined card', async () => {
    const paymentData = {
      cardNumber: '4000000000000002', // Declined card
      expiryDate: '12/25',
      cvv: '123',
      amount: 100,
    };
    
    const result = await processPayment(paymentData);
    
    expect(result.status).toBe('failed');
    expect(result.error).toBe('Card declined');
    // Убедиться, что деньги не списаны
    const transaction = await getTransaction(result.transactionId);
    expect(transaction.status).toBe('failed');
  });
  
  // КРИТИЧНО: Истёкшая карта
  it('should reject expired card', async () => {
    const paymentData = {
      cardNumber: '4242424242424242',
      expiryDate: '01/20', // Expired
      cvv: '123',
      amount: 100,
    };
    
    const result = await processPayment(paymentData);
    
    expect(result.error).toContain('expired');
    expect(result.status).toBe('failed');
  });
});

Валидация данных перед оплатой

describe('Payment Validation', () => {
  // Валидация номера карты (Luhn algorithm)
  it('should validate card number', () => {
    expect(isValidCardNumber('4242424242424242')).toBe(true);
    expect(isValidCardNumber('1234567890123456')).toBe(false);
    expect(isValidCardNumber('424242424242424')).toBe(false); // Too short
  });
  
  // Валидация срока действия
  it('should validate expiry date', () => {
    const futureDate = '12/26';
    const pastDate = '12/20';
    
    expect(isValidExpiryDate(futureDate)).toBe(true);
    expect(isValidExpiryDate(pastDate)).toBe(false);
  });
  
  // Валидация CVV
  it('should validate CVV', () => {
    expect(isValidCVV('123')).toBe(true);
    expect(isValidCVV('12')).toBe(false); // Too short
    expect(isValidCVV('abcd')).toBe(false); // Not a number
  });
  
  // Валидация суммы
  it('should validate payment amount', () => {
    expect(isValidAmount(0.01)).toBe(true); // Минимум
    expect(isValidAmount(0)).toBe(false);
    expect(isValidAmount(-100)).toBe(false);
    expect(isValidAmount(999999999)).toBe(true);
  });
});

Обработка ошибок и edge cases

describe('Payment Error Handling', () => {
  // Timeout при платеже
  it('should handle payment timeout', async () => {
    jest.useFakeTimers();
    const paymentPromise = processPayment(validPaymentData);
    jest.advanceTimersByTime(31000); // Timeout 30s
    
    const result = await paymentPromise;
    expect(result.error).toContain('timeout');
    expect(result.status).toBe('timeout');
    
    // Проверить, что запрос в очереди повтора
    const pendingTransaction = await getPendingTransaction();
    expect(pendingTransaction).toBeDefined();
  });
  
  // Недостаточно средств
  it('should handle insufficient funds', async () => {
    const result = await processPayment({
      ...validPaymentData,
      amount: 999999999,
    });
    
    expect(result.error).toContain('Insufficient funds');
    expect(result.status).toBe('failed');
  });
  
  // 3D Secure / 2FA
  it('should handle 3D Secure authentication', async () => {
    const result = await processPayment(validPaymentData);
    
    if (result.requires3DSecure) {
      expect(result.authUrl).toBeDefined();
      // Пользователь прошёл аутентификацию
      const authResult = await complete3DSecure(result.authUrl);
      expect(authResult.status).toBe('success');
    }
  });
  
  // Сетевая ошибка
  it('should retry on network failure', async () => {
    let attempts = 0;
    jest.spyOn(api, 'processPayment').mockImplementation(async () => {
      attempts++;
      if (attempts < 3) throw new Error('Network error');
      return { status: 'success', transactionId: '123' };
    });
    
    const result = await processPaymentWithRetry(validPaymentData);
    expect(result.status).toBe('success');
    expect(attempts).toBe(3);
  });
});

Проверка интеграции с БД

describe('Payment Database Integration', () => {
  // Транзакция создана в БД
  it('should create transaction record', async () => {
    const paymentData = validPaymentData;
    const result = await processPayment(paymentData);
    
    const transaction = await db.transactions.findById(result.transactionId);
    expect(transaction).toBeDefined();
    expect(transaction.amount).toBe(paymentData.amount);
    expect(transaction.status).toBe('completed');
    expect(transaction.createdAt).toBeDefined();
  });
  
  // Идемпотентность платежа
  it('should prevent duplicate charges', async () => {
    const idempotencyKey = 'unique-key-123';
    
    // Первый платёж
    const result1 = await processPayment(validPaymentData, {
      idempotencyKey,
    });
    
    // Повторный платёж с тем же ключом
    const result2 = await processPayment(validPaymentData, {
      idempotencyKey,
    });
    
    // Должны получить один и тот же результат
    expect(result1.transactionId).toBe(result2.transactionId);
    
    // В БД только одна транзакция
    const transactions = await db.transactions.findByIdempotencyKey(
      idempotencyKey
    );
    expect(transactions.length).toBe(1);
  });
  
  // Возврат средств
  it('should refund payment correctly', async () => {
    const result = await processPayment(validPaymentData);
    const transactionId = result.transactionId;
    
    // Проверяем исходное состояние
    let transaction = await db.transactions.findById(transactionId);
    expect(transaction.status).toBe('completed');
    expect(transaction.amount).toBe(100);
    
    // Запрашиваем возврат
    const refundResult = await refundPayment(transactionId);
    
    // Проверяем что возврат записан
    transaction = await db.transactions.findById(transactionId);
    expect(transaction.status).toBe('refunded');
    expect(transaction.refundedAmount).toBe(100);
    expect(transaction.refundedAt).toBeDefined();
  });
});

Security тесты

describe('Payment Security', () => {
  // Карточные данные не логируются
  it('should never log sensitive data', () => {
    const consoleSpy = jest.spyOn(console, 'log');
    
    processPayment({
      cardNumber: '4242424242424242',
      cvv: '123',
    });
    
    expect(consoleSpy).not.toHaveBeenCalledWith(
      expect.stringContaining('4242')
    );
    expect(consoleSpy).not.toHaveBeenCalledWith(
      expect.stringContaining('123')
    );
  });
  
  // PCI DSS compliance
  it('should use HTTPS and encryption', async () => {
    const request = await capturePaymentRequest();
    expect(request.url).toMatch(/^https:\/\//);
  });
  
  // CSRF protection
  it('should include CSRF token', async () => {
    const csrfToken = getCSRFToken();
    expect(csrfToken).toBeDefined();
    
    const result = await processPayment(validPaymentData, {
      csrfToken,
    });
    expect(result.status).toBe('success');
  });
});

Контрольный список тестирования платежей

  • Успешная оплата работает
  • Отклонённая карта обрабатывается
  • Истёкшая карта обрабатывается
  • Валидация номера карты (Luhn)
  • Валидация срока действия
  • Валидация CVV
  • Обработка timeout
  • Retry механизм работает
  • 3D Secure поддерживается
  • Идемпотентность гарантирована
  • Возвраты работают корректно
  • Чувствительные данные не логируются
  • Используется HTTPS
  • Транзакции записываются в БД
  • Аудит логируется для compliance

Платёжные системы требуют наивысшего уровня тестирования - здесь не может быть ошибок.