> ## Documentation Index
> Fetch the complete documentation index at: https://docs.monei.cc/llms.txt
> Use this file to discover all available pages before exploring further.

# Testing Tools

> Tools and utilities to help test your Monei integration

## Overview

Monei provides testing tools and utilities to help you develop and debug your integration. This guide covers available tools, debugging techniques, and testing strategies.

**What you'll learn:**

* API testing tools
* Debugging techniques
* Mock data generators
* Automated testing
* CI/CD integration

***

## API Testing Tools

### Postman Collection

Import our Postman collection for quick API testing:

<Steps>
  <Step title="Download Collection">
    Download the [Monei Postman Collection](https://docs.monei.cc/postman/collection.json)
  </Step>

  <Step title="Import to Postman">
    Open Postman → Import → Select downloaded file
  </Step>

  <Step title="Configure Environment">
    Create environment with your API key:

    ```json theme={null}
    {
      "api_key": "sk_test_your_key_here",
      "base_url": "https://api.dev.monei.cc"
    }
    ```
  </Step>

  <Step title="Start Testing">
    Use pre-configured requests to test all endpoints
  </Step>
</Steps>

### cURL Examples

Quick API testing from command line:

<CodeGroup>
  ```bash Get Wallet theme={null}
  # Get wallet information
  curl https://api.dev.monei.cc/api/v1/wallet/me \
    -H "x-api-key: sk_test_your_key_here"
  ```

  ```bash Make Deposit theme={null}
  # Initiate card deposit
  curl -X POST https://api.dev.monei.cc/api/v1/wallet/deposit \
    -H "x-api-key: sk_test_your_key_here" \
    -H "Content-Type: application/json" \
    -d '{
      "amount": 5000,
      "method": "CARD",
      "reference": "TEST-DEP-123",
      "card": {
        "cardNumber": "5531886652142950",
        "cvv": "564",
        "expiryMonth": "09",
        "expiryYear": "32",
        "cardHolderName": "TEST USER"
      }
    }'
  ```

  ```bash Get Transactions theme={null}
  # Get transaction history
  curl "https://api.dev.monei.cc/api/v1/transactions/user?page=1&limit=10" \
    -H "x-api-key: sk_test_your_key_here"
  ```
</CodeGroup>

***

## Mock Data Generators

### Generate Test References

<CodeGroup>
  ```javascript Node.js theme={null}
  // Reference generator
  function generateReference(prefix = 'TEST') {
    const timestamp = Date.now();
    const random = Math.random().toString(36).substring(2, 8).toUpperCase();
    return `${prefix}-${timestamp}-${random}`;
  }

  // Usage
  const depositRef = generateReference('DEP');
  console.log(depositRef); // DEP-1708000000-A3X9K2

  const payoutRef = generateReference('PAY');
  console.log(payoutRef); // PAY-1708000000-B7Y4M1

  const billRef = generateReference('BILL');
  console.log(billRef); // BILL-1708000000-C5Z8N3
  ```

  ```python Python theme={null}
  import time
  import random
  import string

  def generate_reference(prefix='TEST'):
      timestamp = int(time.time())
      random_str = ''.join(random.choices(string.ascii_uppercase + string.digits, k=6))
      return f'{prefix}-{timestamp}-{random_str}'

  # Usage
  deposit_ref = generate_reference('DEP')
  print(deposit_ref)  # DEP-1708000000-A3X9K2

  payout_ref = generate_reference('PAY')
  print(payout_ref)  # PAY-1708000000-B7Y4M1
  ```
</CodeGroup>

### Generate Test Data

<CodeGroup>
  ```javascript Node.js theme={null}
  // Test data generator
  const testData = {
    // Test phone numbers
    generatePhone: () => {
      const prefixes = ['0801', '0802', '0803', '0805', '0807', '0808'];
      const prefix = prefixes[Math.floor(Math.random() * prefixes.length)];
      const suffix = Math.floor(Math.random() * 10000000).toString().padStart(7, '0');
      return prefix + suffix;
    },
    
    // Test meter numbers
    generateMeter: () => {
      return Math.floor(Math.random() * 100000000000).toString().padStart(11, '0');
    },
    
    // Test smartcard numbers
    generateSmartcard: () => {
      return Math.floor(Math.random() * 10000000000).toString().padStart(10, '0');
    },
    
    // Test amounts
    generateAmount: (min = 100, max = 50000) => {
      return Math.floor(Math.random() * (max - min + 1)) + min;
    },
    
    // Test card
    testCard: {
      cardNumber: '5531886652142950',
      cvv: '564',
      expiryMonth: '09',
      expiryYear: '32',
      cardHolderName: 'TEST USER'
    }
  };

  // Usage
  console.log('Phone:', testData.generatePhone());
  console.log('Meter:', testData.generateMeter());
  console.log('Amount:', testData.generateAmount());
  ```

  ```python Python theme={null}
  import random

  class TestData:
      @staticmethod
      def generate_phone():
          prefixes = ['0801', '0802', '0803', '0805', '0807', '0808']
          prefix = random.choice(prefixes)
          suffix = str(random.randint(0, 9999999)).zfill(7)
          return prefix + suffix
      
      @staticmethod
      def generate_meter():
          return str(random.randint(0, 99999999999)).zfill(11)
      
      @staticmethod
      def generate_smartcard():
          return str(random.randint(0, 9999999999)).zfill(10)
      
      @staticmethod
      def generate_amount(min_amt=100, max_amt=50000):
          return random.randint(min_amt, max_amt)
      
      @staticmethod
      def test_card():
          return {
              'card_number': '5531886652142950',
              'cvv': '564',
              'expiry_month': '09',
              'expiry_year': '32',
              'card_holder_name': 'TEST USER'
          }

  # Usage
  print(f'Phone: {TestData.generate_phone()}')
  print(f'Meter: {TestData.generate_meter()}')
  print(f'Amount: {TestData.generate_amount()}')
  ```
</CodeGroup>

***

## Automated Testing

### Unit Tests

<CodeGroup>
  ```javascript Node.js (Jest) theme={null}
  // __tests__/wallet.test.js
  const MoneiSDK = require('monei-sdk');

  describe('Wallet Operations', () => {
    let monei;
    
    beforeAll(() => {
      monei = new MoneiSDK({
        apiKey: process.env.MONEI_SANDBOX_API_KEY,
        environment: 'sandbox'
      });
    });
    
    test('should get wallet information', async () => {
      const wallet = await monei.wallet.me();
      
      expect(wallet).toBeDefined();
      expect(wallet.nairaBalance).toBeDefined();
      expect(wallet.subwallets).toBeInstanceOf(Array);
    });
    
    test('should make deposit', async () => {
      const deposit = await monei.wallet.depositWithCard({
        amount: 5000,
        reference: `TEST-${Date.now()}`,
        card: {
          cardNumber: '5531886652142950',
          cvv: '564',
          expiryMonth: '09',
          expiryYear: '32',
          cardHolderName: 'TEST USER'
        }
      });
      
      expect(deposit.reference).toBeDefined();
      expect(deposit.status).toBe('successful');
    });
    
    test('should handle insufficient balance', async () => {
      const wallet = await monei.wallet.me();
      const balance = parseFloat(wallet.nairaBalance);
      
      await expect(
        monei.payout.bankTransfer({
          amount: balance + 10000, // More than balance
          bank: '058',
          accountNumber: '0123456789',
          transactionPin: '1234'
        })
      ).rejects.toThrow('Insufficient balance');
    });
  });
  ```

  ```python Python (pytest) theme={null}
  # tests/test_wallet.py
  import pytest
  from monei import MoneiClient
  import os

  @pytest.fixture
  def monei():
      return MoneiClient(
          api_key=os.getenv('MONEI_SANDBOX_API_KEY'),
          environment='sandbox'
      )

  def test_get_wallet(monei):
      wallet = monei.wallet.me()
      
      assert wallet is not None
      assert hasattr(wallet, 'naira_balance')
      assert isinstance(wallet.subwallets, list)

  def test_make_deposit(monei):
      deposit = monei.wallet.deposit_with_card(
          amount=5000,
          reference=f'TEST-{int(time.time())}',
          card={
              'card_number': '5531886652142950',
              'cvv': '564',
              'expiry_month': '09',
              'expiry_year': '32',
              'card_holder_name': 'TEST USER'
          }
      )
      
      assert deposit.reference is not None
      assert deposit.status == 'successful'

  def test_insufficient_balance(monei):
      wallet = monei.wallet.me()
      balance = float(wallet.naira_balance)
      
      with pytest.raises(Exception, match='Insufficient balance'):
          monei.payout.bank_transfer(
              amount=balance + 10000,
              bank='058',
              account_number='0123456789',
              transaction_pin='1234'
          )
  ```
</CodeGroup>

### Integration Tests

<CodeGroup>
  ```javascript Node.js theme={null}
  // __tests__/integration/bill-payment.test.js
  describe('Bill Payment Flow', () => {
    test('complete airtime purchase flow', async () => {
      // 1. Get billers
      const billers = await monei.bills.getBillers({ category: 'airtime' });
      expect(billers.length).toBeGreaterThan(0);
      
      const mtn = billers.find(b => b.shortName === 'MTN');
      expect(mtn).toBeDefined();
      
      // 2. Validate customer
      const validation = await monei.bills.validate({
        billerId: mtn.billerId,
        customerId: '08012345678',
        type: 'PREPAID'
      });
      
      expect(validation.validated).toBe(true);
      expect(validation.customerName).toBeDefined();
      
      // 3. Make payment
      const payment = await monei.bills.pay({
        billerId: mtn.billerId,
        customerId: '08012345678',
        amount: 100,
        type: 'PREPAID'
      });
      
      expect(payment.status).toBe('successful');
      expect(payment.reference).toBeDefined();
      
      // 4. Verify transaction
      const transaction = await monei.transactions.getByReference(payment.reference);
      expect(transaction.status).toBe('SUCCESS');
    });
  });
  ```

  ```python Python theme={null}
  # tests/integration/test_bill_payment.py
  def test_complete_airtime_flow(monei):
      # 1. Get billers
      billers = monei.bills.get_billers(category='airtime')
      assert len(billers) > 0
      
      mtn = next(b for b in billers if b.short_name == 'MTN')
      assert mtn is not None
      
      # 2. Validate
      validation = monei.bills.validate(
          biller_id=mtn.biller_id,
          customer_id='08012345678',
          type='PREPAID'
      )
      
      assert validation.validated == True
      assert validation.customer_name is not None
      
      # 3. Pay
      payment = monei.bills.pay(
          biller_id=mtn.biller_id,
          customer_id='08012345678',
          amount=100,
          type='PREPAID'
      )
      
      assert payment.status == 'successful'
      assert payment.reference is not None
      
      # 4. Verify
      transaction = monei.transactions.get_by_reference(payment.reference)
      assert transaction.status == 'SUCCESS'
  ```
</CodeGroup>

***

## CI/CD Integration

### GitHub Actions

<CodeGroup>
  ```yaml .github/workflows/test.yml theme={null}
  name: Test Monei Integration

  on:
    push:
      branches: [main, develop]
    pull_request:
      branches: [main]

  jobs:
    test:
      runs-on: ubuntu-latest
      
      steps:
        - uses: actions/checkout@v3
        
        - name: Setup Node.js
          uses: actions/setup-node@v3
          with:
            node-version: '18'
        
        - name: Install dependencies
          run: npm ci
        
        - name: Run tests
          env:
            MONEI_SANDBOX_API_KEY: ${{ secrets.MONEI_SANDBOX_API_KEY }}
          run: npm test
        
        - name: Upload coverage
          uses: codecov/codecov-action@v3
  ```
</CodeGroup>

### GitLab CI

<CodeGroup>
  ```yaml .gitlab-ci.yml theme={null}
  stages:
    - test

  test:
    stage: test
    image: node:18
    
    variables:
      MONEI_SANDBOX_API_KEY: $MONEI_SANDBOX_API_KEY
    
    before_script:
      - npm ci
    
    script:
      - npm test
    
    coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'
    
    artifacts:
      reports:
        coverage_report:
          coverage_format: cobertura
          path: coverage/cobertura-coverage.xml
  ```
</CodeGroup>

***

## Debugging Tools

### Request/Response Logging

<CodeGroup>
  ```javascript Node.js theme={null}
  // Debug middleware
  const debug = require('debug')('monei:api');

  class MoneiDebugger {
    constructor(sdk) {
      this.sdk = sdk;
      this.interceptRequests();
    }
    
    interceptRequests() {
      const originalFetch = global.fetch;
      
      global.fetch = async (...args) => {
        const [url, options] = args;
        
        // Log request
        debug('REQUEST:', {
          url,
          method: options?.method || 'GET',
          headers: options?.headers,
          body: options?.body
        });
        
        const start = Date.now();
        const response = await originalFetch(...args);
        const duration = Date.now() - start;
        
        // Log response
        const responseData = await response.clone().json();
        debug('RESPONSE:', {
          status: response.status,
          duration: `${duration}ms`,
          data: responseData
        });
        
        return response;
      };
    }
  }

  // Usage
  const monei = new MoneiSDK({ apiKey: process.env.MONEI_API_KEY });
  new MoneiDebugger(monei);

  // Enable debug logs
  // DEBUG=monei:* node your-script.js
  ```

  ```python Python theme={null}
  # Debug logger
  import logging
  import requests
  import time

  # Configure logging
  logging.basicConfig(level=logging.DEBUG)
  logger = logging.getLogger('monei.api')

  class MoneiDebugger:
      def __init__(self, client):
          self.client = client
          self.intercept_requests()
      
      def intercept_requests(self):
          original_request = requests.request
          
          def debug_request(*args, **kwargs):
              # Log request
              logger.debug(f'REQUEST: {kwargs.get("method")} {kwargs.get("url")}')
              logger.debug(f'Headers: {kwargs.get("headers")}')
              logger.debug(f'Body: {kwargs.get("json")}')
              
              start = time.time()
              response = original_request(*args, **kwargs)
              duration = (time.time() - start) * 1000
              
              # Log response
              logger.debug(f'RESPONSE: {response.status_code} ({duration:.0f}ms)')
              logger.debug(f'Data: {response.json()}')
              
              return response
          
          requests.request = debug_request

  # Usage
  monei = MoneiClient(api_key=os.getenv('MONEI_API_KEY'))
  MoneiDebugger(monei)
  ```
</CodeGroup>

### Error Tracking

<CodeGroup>
  ```javascript Sentry Integration theme={null}
  const Sentry = require('@sentry/node');

  Sentry.init({
    dsn: process.env.SENTRY_DSN,
    environment: process.env.NODE_ENV,
    tracesSampleRate: 1.0,
  });

  // Wrap Monei calls
  async function safeMoneiCall(fn, context) {
    const transaction = Sentry.startTransaction({
      op: 'monei.api',
      name: context
    });
    
    try {
      const result = await fn();
      transaction.setStatus('ok');
      return result;
    } catch (error) {
      transaction.setStatus('error');
      Sentry.captureException(error, {
        contexts: {
          monei: { operation: context }
        }
      });
      throw error;
    } finally {
      transaction.finish();
    }
  }

  // Usage
  const wallet = await safeMoneiCall(
    () => monei.wallet.me(),
    'wallet.me'
  );
  ```
</CodeGroup>

***

## Performance Testing

### Load Testing

<CodeGroup>
  ```javascript k6 Script theme={null}
  import http from 'k6/http';
  import { check, sleep } from 'k6';

  export const options = {
    stages: [
      { duration: '30s', target: 10 },  // Ramp up
      { duration: '1m', target: 10 },   // Stay at 10
      { duration: '30s', target: 0 },   // Ramp down
    ],
  };

  export default function () {
    const url = 'https://api.dev.monei.cc/api/v1/wallet/me';
    const params = {
      headers: {
        'x-api-key': __ENV.MONEI_API_KEY,
      },
    };
    
    const response = http.get(url, params);
    
    check(response, {
      'status is 200': (r) => r.status === 200,
      'response time < 500ms': (r) => r.timings.duration < 500,
    });
    
    sleep(1);
  }

  // Run: k6 run --env MONEI_API_KEY=sk_test_... load-test.js
  ```
</CodeGroup>

***

## Best Practices

<CardGroup cols={2}>
  <Card title="Test Early" icon="clock">
    Start testing during development, not after
  </Card>

  <Card title="Automate Tests" icon="robot">
    Create automated test suites for CI/CD
  </Card>

  <Card title="Use Mock Data" icon="database">
    Generate realistic test data
  </Card>

  <Card title="Test Edge Cases" icon="triangle-exclamation">
    Test failures, timeouts, and errors
  </Card>

  <Card title="Monitor Tests" icon="chart-line">
    Track test coverage and results
  </Card>

  <Card title="Keep Tests Fast" icon="bolt">
    Optimize test execution time
  </Card>
</CardGroup>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Sandbox" icon="flask" href="/testing/sandbox">
    Learn about sandbox environment
  </Card>

  <Card title="Security" icon="shield" href="/security/guidelines">
    Security best practices
  </Card>

  <Card title="Error Handling" icon="triangle-exclamation" href="/core-concepts/error-handling">
    Handle errors properly
  </Card>

  <Card title="Webhooks" icon="webhook" href="/security/webhooks">
    Test webhook integration
  </Card>
</CardGroup>
