Mock API for Integration Testing
The Mock Flask API provides a lightweight, self-contained REST API for integration testing. It’s perfect for testing the socialseed-e2e framework itself or as a reference implementation when building your own tests.
Overview
The mock API simulates a real-world REST API with:
Health check endpoint
Complete user CRUD operations
Authentication system (login/register)
In-memory data storage with seed data
Pagination and search capabilities
Proper HTTP status codes and error handling
Quick Start
Running the Mock API
Option 1: Direct Execution (for manual testing)
# From project root
python tests/fixtures/mock_api.py
Output:
🚀 Starting Mock API Server...
📍 URL: http://localhost:8765
📖 Endpoints:
GET /health
GET /api/users
POST /api/users
GET /api/users/{id}
PUT /api/users/{id}
DELETE /api/users/{id}
POST /api/auth/login
POST /api/auth/register
Press Ctrl+C to stop
Option 2: As Pytest Fixture (for automated tests)
import requests
def test_api(mock_api_url):
"""Test using the mock API fixture."""
response = requests.get(f"{mock_api_url}/health")
assert response.status_code == 200
Available Endpoints
Health Check
GET /health
Returns server status and timestamp.
Response:
{
"status": "healthy",
"timestamp": "2026-01-31T12:00:00",
"service": "mock-api",
"version": "1.0.0"
}
Users CRUD
List Users
GET /api/users?page=1&limit=10&search=keyword
Query parameters:
page: Page number (default: 1)limit: Items per page (default: 10)search: Search in name or email (optional)
Response:
{
"items": [...],
"total": 2,
"page": 1,
"limit": 10,
"total_pages": 1
}
Create User
POST /api/users
Request body:
{
"email": "user@example.com",
"password": "secret123",
"name": "John Doe",
"role": "user"
}
Response: 201 Created
{
"id": "uuid-here",
"email": "user@example.com",
"name": "John Doe",
"role": "user",
"created_at": "...",
"updated_at": "..."
}
Get User
GET /api/users/{id}
Response: 200 OK or 404 Not Found
Update User
PUT /api/users/{id}
Request body:
{
"name": "Updated Name",
"email": "new@example.com",
"role": "admin"
}
Response: 200 OK
Delete User
DELETE /api/users/{id}
Response: 204 No Content
Authentication
Login
POST /api/auth/login
Request body:
{
"email": "admin@example.com",
"password": "admin123"
}
Response:
{
"token": "auth-token-here",
"user": {...}
}
Register
POST /api/auth/register
Request body:
{
"email": "new@example.com",
"password": "secret123",
"name": "New User"
}
Response: 201 Created
{
"token": "auth-token-here",
"user": {...}
}
Seeded Data
The mock API comes with 2 pre-configured users:
Password |
Role |
Purpose |
|
|---|---|---|---|
admin@example.com |
admin123 |
admin |
Admin testing |
user@example.com |
user123 |
user |
Regular user testing |
Pytest Fixtures
Available Fixtures
mock_api_server
Session-scoped fixture that starts the mock API in a background thread.
def test_with_server(mock_api_server):
url = mock_api_server.get_base_url()
# Server is already running
mock_api_url
Convenience fixture providing the base URL string.
def test_with_url(mock_api_url):
response = requests.get(f"{mock_api_url}/health")
mock_api_reset
Function-scoped fixture that resets data before each test.
def test_with_clean_data(mock_api_url, mock_api_reset):
# API is reset to initial state with 2 seeded users
response = requests.get(f"{mock_api_url}/api/users")
assert response.json()['total'] == 2
sample_user_data
Provides sample user data for testing.
def test_create(mock_api_url, sample_user_data):
response = requests.post(
f"{mock_api_url}/api/users",
json=sample_user_data
)
assert response.status_code == 201
admin_credentials / user_credentials
Pre-configured credentials for seeded users.
def test_login(mock_api_url, admin_credentials):
response = requests.post(
f"{mock_api_url}/api/auth/login",
json=admin_credentials
)
assert response.status_code == 200
Fixture Scopes
Fixture |
Scope |
Description |
|---|---|---|
|
session |
Server runs once for all tests |
|
session |
URL string from server |
|
function |
Resets data before each test |
|
function |
Fresh sample data each test |
|
function |
Admin credentials |
|
function |
User credentials |
For AI Agents
Understanding the Architecture
tests/
├── fixtures/
│ └── mock_api.py # MockAPIServer class
├── conftest.py # Pytest fixtures
└── integration/
└── test_mock_api_integration.py # Example tests
Key Classes
MockAPIServer
The main server class that wraps Flask:
from tests.fixtures.mock_api import MockAPIServer
# Create instance
server = MockAPIServer(port=8765)
# Access data
print(server.users) # Dict of users
print(server.auth_tokens) # Dict of active tokens
# Control server
server.run(debug=True) # Blocking
server.reset() # Reset to initial state
url = server.get_base_url() # Get "http://localhost:8765"
Writing Tests with Mock API
Pattern 1: Simple API Test
import requests
def test_health_check(mock_api_url):
"""Basic health check test."""
response = requests.get(f"{mock_api_url}/health")
assert response.status_code == 200
data = response.json()
assert data['status'] == 'healthy'
Pattern 2: CRUD Operations Test
def test_user_lifecycle(mock_api_url, mock_api_reset):
"""Test complete user CRUD with clean state."""
# Create
create_resp = requests.post(
f"{mock_api_url}/api/users",
json={"email": "test@test.com", "password": "pass", "name": "Test"}
)
assert create_resp.status_code == 201
user_id = create_resp.json()['id']
# Read
get_resp = requests.get(f"{mock_api_url}/api/users/{user_id}")
assert get_resp.status_code == 200
# Update
update_resp = requests.put(
f"{mock_api_url}/api/users/{user_id}",
json={"name": "Updated"}
)
assert update_resp.json()['name'] == "Updated"
# Delete
delete_resp = requests.delete(f"{mock_api_url}/api/users/{user_id}")
assert delete_resp.status_code == 204
Pattern 3: Authentication Flow
def test_auth_flow(mock_api_url, mock_api_reset):
"""Test registration and login flow."""
# Register new user
register_resp = requests.post(
f"{mock_api_url}/api/auth/register",
json={"email": "new@test.com", "password": "pass", "name": "New"}
)
assert register_resp.status_code == 201
token = register_resp.json()['token']
# Login with same credentials
login_resp = requests.post(
f"{mock_api_url}/api/auth/login",
json={"email": "new@test.com", "password": "pass"}
)
assert login_resp.status_code == 200
assert 'token' in login_resp.json()
Best Practices for AI Agents
Always use
mock_api_resetfor tests that modify dataEnsures tests don’t interfere with each other
Provides predictable initial state
Use seeded credentials for authentication tests
admin_credentialsanduser_credentialsfixturesAvoid creating users just to test login
Test error cases
404 for missing resources
400 for invalid input
409 for duplicates
401 for invalid auth
Verify response structure
Check status codes
Verify JSON structure
Ensure passwords are NOT returned
Example: Complete Test Suite
import requests
import pytest
class TestUserAPI:
"""Comprehensive tests for user endpoints."""
def test_list_users_pagination(self, mock_api_url):
"""Test pagination works correctly."""
resp = requests.get(f"{mock_api_url}/api/users?limit=1")
data = resp.json()
assert len(data['items']) == 1
assert data['total_pages'] >= 2
def test_search_users(self, mock_api_url):
"""Test search functionality."""
resp = requests.get(f"{mock_api_url}/api/users?search=admin")
data = resp.json()
assert all('admin' in u['email'] for u in data['items'])
def test_create_duplicate_fails(self, mock_api_url):
"""Test duplicate email returns 409."""
resp = requests.post(
f"{mock_api_url}/api/users",
json={"email": "admin@example.com", "password": "x", "name": "X"}
)
assert resp.status_code == 409
Troubleshooting
Port Already in Use
If port 8765 is occupied:
# Use different port
server = MockAPIServer(port=9999)
Server Not Starting in Tests
The fixture has built-in retry logic (30 retries, 0.1s delay). If it fails:
# Check if something else is using port 8765
lsof -i :8765
# Or modify the port in conftest.py
server = MockAPIServer(port=9999) # Change port
Data Persistence Between Tests
By default, data persists between tests for performance. Use mock_api_reset to clean:
def test_with_reset(mock_api_url, mock_api_reset):
# Data is fresh for this test
pass
def test_without_reset(mock_api_url):
# Data persists from previous tests
pass
Advanced Usage
Customizing Seed Data
Edit tests/fixtures/mock_api.py:
def _seed_data(self) -> None:
"""Override with your own seed data."""
self.users = {
"custom-id": {
"id": "custom-id",
"email": "custom@example.com",
"password": "custompass",
"name": "Custom User",
"role": "user",
"created_at": datetime.utcnow().isoformat(),
"updated_at": datetime.utcnow().isoformat(),
}
}
Adding Custom Endpoints
Extend the MockAPIServer class:
class CustomMockAPI(MockAPIServer):
def _register_routes(self):
super()._register_routes()
@self.app.route('/api/custom', methods=['GET'])
def custom_endpoint():
return jsonify({"custom": "data"})
See Also
Writing Tests - General test writing guide
API Reference - Framework API documentation
tests/integration/test_mock_api_integration.py- Example tests