API Testing Strategies: Common Questions Answered
APIs are the connective tissue of modern software. Every microservice, third-party integration, and mobile backend depends on APIs working correctly. Yet API testing is often treated as an afterthought, squeezed in before release. This FAQ covers the strategies, tools, and approaches that make API testing reliable and efficient.
Key Takeaways
- Test at multiple levels: unit, integration, contract, and end-to-end
- Automate everything: manual API testing does not scale
- Mock external dependencies: your tests should not depend on third-party uptime
- SearchHive APIs can be tested with 500 free credits, no commitments
What Is API Testing?
API testing sends requests to an API endpoint and validates the response against expected behavior. Unlike UI testing, API testing operates at the protocol level -- you send HTTP requests (GET, POST, PUT, DELETE) and check status codes, response bodies, headers, and latency.
The core validation types:
- Functional: Does the endpoint return the correct data?
- Performance: Does it respond within acceptable time limits?
- Security: Are there authentication, authorization, or injection vulnerabilities?
- Reliability: Does it handle errors, edge cases, and load gracefully?
import requests
# Basic API test example
response = requests.get(
"https://api.example.com/v1/users/1",
headers={"Authorization": "Bearer test_token"}
)
assert response.status_code == 200
data = response.json()
assert data["id"] == 1
assert "email" in data
assert response.elapsed.total_seconds() < 1.0
What Are the Different Types of API Testing?
1. Unit Testing
Tests individual API functions or methods in isolation. Fastest to run, lowest level.
# Unit test for an API helper function
def format_search_params(query, limit=10):
return {"q": query, "num": limit, "format": "json"}
def test_format_search_params():
result = format_search_params("python tutorial", 20)
assert result["q"] == "python tutorial"
assert result["num"] == 20
2. Integration Testing
Tests how multiple API components work together, including database interactions and internal service calls.
3. Contract Testing
Verifies that API consumers and providers agree on the same interface (request/response schema). Tools like Pact are popular for this.
4. End-to-End Testing
Tests complete workflows through the API, from request to response, often involving multiple endpoints.
5. Load/Stress Testing
Tests API performance under high traffic. Tools: k6, Locust, Artillery.
What Are the Best API Testing Tools?
| Tool | Type | Best For | Pricing |
|---|---|---|---|
| pytest + requests | Framework | Python developers | Free |
| Postman | GUI + CLI | Team collaboration | Free / $14/mo |
| Insomnia | GUI | REST/GraphQL | Free / $7/mo |
| k6 | CLI | Load testing | Free / Pro |
| SoapUI | GUI | SOAP + REST | Free / $659/yr |
| Hoppscotch | GUI | Open-source Postman alt | Free / Self-hosted |
| Playwright | Framework | E2E with browser | Free |
For development teams, pytest with the requests library is the most flexible approach. It integrates with CI/CD pipelines, supports fixtures for test data, and generates clear failure reports.
How Do I Test an External API Without Hitting Production?
Mocking external APIs is critical for reliable tests. Three approaches:
1. Mock with Python unittest.mock
from unittest.mock import patch, MagicMock
@patch("requests.get")
def test_search_api(mock_get):
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {
"results": [
{"title": "Python Guide", "url": "https://example.com/python"}
],
"total": 1
}
mock_get.return_value = mock_response
# Your code under test calls requests.get internally
result = call_search_api("python guide")
assert len(result["results"]) == 1
mock_get.assert_called_once()
2. Record and replay with VCR.py
VCR.py records real API responses and replays them in tests:
import vcr
with vcr.use_cassette("fixtures/search_response.yaml"):
response = requests.get("https://api.searchhive.dev/v1/swiftsearch",
params={"query": "test"})
# Response is replayed from cassette, no real HTTP call
3. Run a local mock server
Tools like WireMock, Mockoon, or Prism let you run a local server that mimics the real API.
How Do I Test SearchHive APIs?
SearchHive provides three APIs that can be tested with the same approach as any REST API:
import requests, os
API_KEY = os.environ.get("SEARCHHIVE_API_KEY", "your_test_key")
BASE = "https://api.searchhive.dev/v1"
headers = {"Authorization": f"Bearer {API_KEY}"}
# Test SwiftSearch
def test_swiftsearch():
resp = requests.get(f"{BASE}/swiftsearch", headers=headers,
params={"query": "python web scraping", "num_results": 5})
assert resp.status_code == 200
data = resp.json()
assert "results" in data
assert len(data["results"]) <= 5
for r in data["results"]:
assert "title" in r
assert "url" in r
# Test ScrapeForge
def test_scrapeforge():
resp = requests.get(f"{BASE}/scrapeforge", headers=headers,
params={"url": "https://example.com", "format": "markdown"})
assert resp.status_code == 200
data = resp.json()
assert "content" in data
assert len(data["content"]) > 0
# Test DeepDive
def test_deepdive():
resp = requests.get(f"{BASE}/deepdive", headers=headers,
params={"url": "https://example.com", "extract": "structured"})
assert resp.status_code == 200
data = resp.json()
assert "data" in data or "content" in data
With 500 free credits on signup, you can run meaningful integration tests against the live API without any cost. For CI/CD pipelines, use VCR.py to record responses and replay them, then run live tests on a schedule.
How Do I Handle Authentication in API Tests?
Most APIs use one of these auth methods:
- Bearer tokens: Include in the
Authorization: Bearer <token>header - API keys: Pass as a query parameter or header
- OAuth 2.0: Requires a token exchange flow
For tests, store credentials in environment variables, never in code:
import os
API_KEY = os.environ["SEARCHHIVE_API_KEY"]
headers = {"Authorization": f"Bearer {API_KEY}"}
# In CI/CD, set the env var in your pipeline config
# GitHub Actions: env: SEARCHHIVE_API_KEY: ${{ secrets.SEARCHHIVE_API_KEY }}
Test both successful authentication and failure cases:
def test_unauthorized_access():
resp = requests.get(f"{BASE}/swiftsearch",
headers={"Authorization": "Bearer invalid_key"})
assert resp.status_code == 401
What Should I Assert in API Tests?
Essential assertions for every API response:
- HTTP status codes reference: Matches expected (200, 201, 400, 404, etc.)
- Response schema: All expected fields present and correctly typed
- Business logic: Values make sense (positive IDs, valid dates, etc.)
- Headers: Content-Type, rate limit headers, caching headers
- Latency: Response time within SLA (assert with pytest timeout)
- Pagination: Correct page size, total count, next/prev links
def test_pagination():
resp = requests.get(f"{BASE}/swiftsearch", headers=headers,
params={"query": "test", "num_results": 10, "page": 1})
assert resp.status_code == 200
data = resp.json()
assert len(data["results"]) <= 10
if "total_pages" in data:
assert data["total_pages"] >= 1
How Do I Test API Error Handling?
Error handling is where most API bugs live. Test these scenarios:
- Invalid parameters: 400 Bad Request with descriptive error message
- Missing auth: 401 Unauthorized
- Insufficient permissions: 403 Forbidden
- Nonexistent resource: 404 Not Found
- Rate limiting: 429 Too Many Requests
- Server errors: 5xx codes should return structured error bodies
def test_error_responses():
# Missing required parameter
resp = requests.get(f"{BASE}/swiftsearch", headers=headers)
assert resp.status_code in [400, 422]
# Invalid URL for scraping
resp = requests.get(f"{BASE}/scrapeforge", headers=headers,
params={"url": "not-a-url", "format": "markdown"})
assert resp.status_code == 400
How Do I Set Up API Testing in CI/CD?
A minimal CI/CD API test setup with GitHub Actions:
- Write tests with pytest in a
tests/directory - Create a
.github/workflows/api-tests.ymlfile - Store API keys as repository secrets
- Run tests on push and on schedule
Tests should run in under 5 minutes. Keep the test suite focused on critical paths -- you do not need to test every single parameter combination.
What Is Contract Testing and Why Does It Matter?
Contract testing verifies that the API provider and consumer agree on the interface. This is critical for microservice architectures where multiple teams depend on each other's APIs.
Tools like Pact let consumer and provider teams test independently:
- Consumer team writes a test that defines expected request/response
- This "contract" is published to a Pact broker
- Provider team verifies their API against all consumer contracts
This catches breaking changes before they reach production, even when services are developed by different teams.
Get Started With API Testing
Reliable API testing starts with picking the right level for each test type: unit tests for internal logic, integration tests for database and service interactions, and contract tests for inter-team APIs. Use mocks for external dependencies, store credentials in environment variables, and run everything in CI/CD.
If you are building data pipelines with web APIs, SearchHive gives you search, scraping, and extraction in one platform. The 500 free credits let you test against real endpoints. Check the docs for API reference and Python examples.