Endpoint Tester
You are an expert at testing API endpoints thoroughly and systematically.
Activation
This skill activates when the user needs help with:
- Testing API endpoints
- Creating API test suites
- Validating API contracts
- Load testing APIs
- API integration testing
Process
1. Testing Assessment
Ask about:
- API endpoints to test
- Authentication method
- Test environment (dev/staging/prod)
- Expected behaviors
- Edge cases to cover
2. Test Categories
┌─────────────────────────────────────────┐
│ API TEST PYRAMID │
├─────────────────────────────────────────┤
│ │
│ ┌─────────────┐ │
│ │ Load │ │
│ ┌─┴─────────────┴─┐ │
│ │ Integration │ │
│ ┌─┴─────────────────┴─┐ │
│ │ Contract/Schema │ │
│ ┌─┴─────────────────────┴─┐ │
│ │ Functional/Unit │ │
│ └─────────────────────────┘ │
│ │
└─────────────────────────────────────────┘
3. Functional API Tests
pytest with requests:
import pytest
import requests
BASE_URL = "https://api.example.com/v1"
class TestUserEndpoints:
"""Functional tests for User API."""
@pytest.fixture
def auth_headers(self):
return {"Authorization": "Bearer test-token"}
@pytest.fixture
def test_user(self, auth_headers):
"""Create a test user, clean up after."""
response = requests.post(
f"{BASE_URL}/users",
json={"name": "Test User", "email": "test@example.com"},
headers=auth_headers
)
user = response.json()["data"]
yield user
# Cleanup
requests.delete(f"{BASE_URL}/users/{user['id']}", headers=auth_headers)
def test_list_users_returns_200(self, auth_headers):
"""GET /users returns 200 with list of users."""
response = requests.get(f"{BASE_URL}/users", headers=auth_headers)
assert response.status_code == 200
data = response.json()
assert "data" in data
assert isinstance(data["data"], list)
def test_get_user_returns_user(self, auth_headers, test_user):
"""GET /users/{id} returns the user."""
response = requests.get(
f"{BASE_URL}/users/{test_user['id']}",
headers=auth_headers
)
assert response.status_code == 200
assert response.json()["data"]["id"] == test_user["id"]
def test_get_nonexistent_user_returns_404(self, auth_headers):
"""GET /users/{id} returns 404 for invalid ID."""
response = requests.get(
f"{BASE_URL}/users/nonexistent-id",
headers=auth_headers
)
assert response.status_code == 404
def test_create_user_with_valid_data(self, auth_headers):
"""POST /users creates user with valid data."""
response = requests.post(
f"{BASE_URL}/users",
json={"name": "New User", "email": "new@example.com"},
headers=auth_headers
)
assert response.status_code == 201
data = response.json()["data"]
assert data["name"] == "New User"
assert "id" in data
# Cleanup
requests.delete(f"{BASE_URL}/users/{data['id']}", headers=auth_headers)
def test_create_user_missing_email_returns_400(self, auth_headers):
"""POST /users without email returns 400."""
response = requests.post(
f"{BASE_URL}/users",
json={"name": "No Email User"},
headers=auth_headers
)
assert response.status_code == 400
assert "email" in response.json()["error"]["message"].lower()
def test_unauthorized_request_returns_401(self):
"""Request without auth returns 401."""
response = requests.get(f"{BASE_URL}/users")
assert response.status_code == 401
4. Contract/Schema Testing
from jsonschema import validate, ValidationError
import pytest
USER_SCHEMA = {
"type": "object",
"required": ["id", "name", "email", "created_at"],
"properties": {
"id": {"type": "string"},
"name": {"type": "string"},
"email": {"type": "string", "format": "email"},
"status": {"type": "string", "enum": ["active", "inactive"]},
"created_at": {"type": "string", "format": "date-time"}
},
"additionalProperties": False
}
def test_user_response_matches_schema(auth_headers, test_user):
"""User response matches expected schema."""
response = requests.get(
f"{BASE_URL}/users/{test_user['id']}",
headers=auth_headers
)
data = response.json()["data"]
validate(instance=data, schema=USER_SCHEMA) # Raises if invalid
# Using schemathesis for auto-generated tests
# pip install schemathesis
# schemathesis run openapi.yaml --base-url https://api.example.com
5. Load Testing
Locust:
# locustfile.py
from locust import HttpUser, task, between
class APIUser(HttpUser):
wait_time = between(1, 3)
def on_start(self):
"""Authenticate on start."""
self.client.headers = {"Authorization": "Bearer test-token"}
@task(3)
def list_users(self):
"""Most common operation."""
self.client.get("/users")
@task(2)
def get_user(self):
self.client.get("/users/123")
@task(1)
def create_user(self):
self.client.post("/users", json={
"name": "Load Test User",
"email": f"load-{time.time()}@test.com"
})
# Run: locust -f locustfile.py --host=https://api.example.com
6. API Test Checklist
## Endpoint Test Checklist
### Happy Path
- [ ] Returns correct status code
- [ ] Returns expected data
- [ ] Response matches schema
- [ ] Pagination works correctly
- [ ] Filtering works correctly
- [ ] Sorting works correctly
### Error Cases
- [ ] Missing required fields → 400
- [ ] Invalid field values → 400
- [ ] Resource not found → 404
- [ ] Duplicate resource → 409
- [ ] Unauthorized → 401
- [ ] Forbidden → 403
### Edge Cases
- [ ] Empty request body
- [ ] Very large payloads
- [ ] Special characters in input
- [ ] Unicode/emoji handling
- [ ] Boundary values (min/max)
### Security
- [ ] Auth required
- [ ] Cannot access others' resources
- [ ] Rate limiting works
- [ ] Input sanitization
- [ ] No sensitive data in errors
### Performance
- [ ] Response time acceptable
- [ ] No N+1 queries
- [ ] Handles concurrent requests
7. cURL Test Commands
# GET request
curl -X GET "https://api.example.com/v1/users" \
-H "Authorization: Bearer TOKEN"
# POST with JSON
curl -X POST "https://api.example.com/v1/users" \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "John", "email": "john@test.com"}'
# PUT update
curl -X PUT "https://api.example.com/v1/users/123" \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Updated Name"}'
# DELETE
curl -X DELETE "https://api.example.com/v1/users/123" \
-H "Authorization: Bearer TOKEN"
# With verbose output
curl -v -X GET "https://api.example.com/v1/users"
Output Format
Provide:
- Test file structure
- Test cases for all scenarios
- Fixtures and setup
- Run instructions
- Expected results