Skip to content

Testing Guide

garotm edited this page Nov 29, 2024 · 1 revision

Testing Guide

Overview

This guide outlines the testing practices and standards for the fleXRP project. We use pytest as our primary testing framework and aim for comprehensive test coverage across all components.

Test Structure

Directory Layout

tests/
├── unit/
│   ├── api/
│   ├── core/
│   └── services/
├── integration/
│   ├── api/
│   └── services/
├── e2e/
├── fixtures/
└── conftest.py

Test Categories

1. Unit Tests

Test individual components in isolation.

# tests/unit/services/test_payment.py
import pytest
from src.services.payment import PaymentService

def test_payment_creation():
    """Test creating a new payment."""
    service = PaymentService()
    payment = service.create_payment(amount=100.00)
    
    assert payment.amount == 100.00
    assert payment.status == "pending"

def test_payment_validation():
    """Test payment validation."""
    service = PaymentService()
    
    with pytest.raises(ValueError):
        service.create_payment(amount=-100.00)

2. Integration Tests

Test component interactions.

# tests/integration/test_payment_flow.py
import pytest
from src.services import PaymentService
from src.services import WalletService

@pytest.mark.integration
def test_payment_processing():
    """Test complete payment processing flow."""
    payment_service = PaymentService()
    wallet_service = WalletService()
    
    payment = payment_service.create_payment(amount=100.00)
    result = wallet_service.process_payment(payment)
    
    assert result.status == "completed"
    assert wallet_service.get_balance() == 900.00

3. End-to-End Tests

Test complete user scenarios.

# tests/e2e/test_payment_api.py
import pytest
from src.app import create_app

@pytest.mark.e2e
def test_payment_api_flow():
    """Test complete payment API flow."""
    app = create_app('testing')
    client = app.test_client()
    
    # Create payment
    response = client.post('/api/payments', json={
        'amount': 100.00,
        'currency': 'XRP'
    })
    assert response.status_code == 201
    payment_id = response.json['id']
    
    # Check status
    response = client.get(f'/api/payments/{payment_id}')
    assert response.status_code == 200
    assert response.json['status'] == "pending"

Test Fixtures

Basic Fixtures

# tests/conftest.py
import pytest
from src.app import create_app
from src.db import db

@pytest.fixture
def app():
    """Create test app."""
    app = create_app('testing')
    return app

@pytest.fixture
def client(app):
    """Create test client."""
    return app.test_client()

@pytest.fixture
def db_session():
    """Provide test database session."""
    db.create_all()
    yield db.session
    db.session.remove()
    db.drop_all()

Mock Fixtures

# tests/fixtures/mocks.py
import pytest
from unittest.mock import Mock

@pytest.fixture
def mock_xrpl_client():
    """Mock XRPL client."""
    client = Mock()
    client.get_balance.return_value = 1000.00
    return client

@pytest.fixture
def mock_payment_response():
    """Mock payment response."""
    return {
        'id': 'test_payment_id',
        'status': 'completed',
        'amount': 100.00
    }

Running Tests

Basic Test Execution

# Run all tests
pytest

# Run specific test file
pytest tests/unit/test_payment.py

# Run specific test
pytest tests/unit/test_payment.py::test_payment_creation

# Run marked tests
pytest -m integration

Test Coverage

# Run tests with coverage
pytest --cov=src tests/

# Generate HTML coverage report
pytest --cov=src --cov-report=html tests/

Test Markers

Using Markers

# pytest.ini
[pytest]
markers =
    unit: Unit tests
    integration: Integration tests
    e2e: End-to-end tests
    slow: Slow running tests

# Using markers in tests
@pytest.mark.slow
def test_long_running_process():
    """Test that takes longer to execute."""
    pass

@pytest.mark.integration
def test_database_integration():
    """Test database operations."""
    pass

Mocking

Example Mocks

from unittest.mock import Mock, patch

def test_payment_processing():
    """Test payment processing with mocked dependencies."""
    with patch('src.services.xrpl_client') as mock_client:
        mock_client.send_payment.return_value = {
            'status': 'success',
            'tx_hash': 'abc123'
        }
        
        service = PaymentService(client=mock_client)
        result = service.process_payment(amount=100.00)
        
        assert result.status == 'completed'
        mock_client.send_payment.assert_called_once()

Async Testing

Testing Async Code

import pytest
import asyncio

@pytest.mark.asyncio
async def test_async_payment():
    """Test async payment processing."""
    service = AsyncPaymentService()
    result = await service.process_payment(amount=100.00)
    assert result.status == 'completed'

@pytest.fixture
async def async_client():
    """Async client fixture."""
    client = AsyncClient()
    await client.connect()
    yield client
    await client.disconnect()

Test Data Management

Using Test Data

# tests/fixtures/data.py
import json
import pytest

@pytest.fixture
def sample_payment_data():
    """Load sample payment data."""
    with open('tests/fixtures/payment_data.json') as f:
        return json.load(f)

def test_payment_creation(sample_payment_data):
    """Test payment creation with sample data."""
    service = PaymentService()
    payment = service.create_payment(**sample_payment_data)
    assert payment.amount == sample_payment_data['amount']

Performance Testing

Load Tests

import pytest
from locust import HttpUser, task, between

class PaymentUser(HttpUser):
    wait_time = between(1, 3)
    
    @task
    def create_payment(self):
        """Test payment creation under load."""
        self.client.post("/api/payments", json={
            "amount": 100.00,
            "currency": "XRP"
        })

Continuous Integration

GitHub Actions Configuration

# .github/workflows/test.yml
name: Tests
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Set up Python
        uses: actions/setup-python@v2
        with:
          python-version: '3.11'
      - name: Install dependencies
        run: |
          pip install -r requirements.txt
          pip install -r requirements-dev.txt
      - name: Run tests
        run: |
          pytest --cov=src tests/

Best Practices

Testing Guidelines

  1. Write tests before code (TDD)
  2. Keep tests simple and focused
  3. Use meaningful test names
  4. Don't test implementation details
  5. Maintain test independence
  6. Clean up test data
  7. Use appropriate assertions
  8. Document complex test scenarios

Common Patterns

def test_should_succeed():
    """Test successful scenario."""
    # Arrange
    service = PaymentService()
    
    # Act
    result = service.process_payment(100.00)
    
    # Assert
    assert result.status == "completed"

def test_should_fail():
    """Test failure scenario."""
    # Arrange
    service = PaymentService()
    
    # Act & Assert
    with pytest.raises(ValueError):
        service.process_payment(-100.00)

This documentation is maintained by the fleXRP team.