APITestka is a lightweight, cross-platform Python framework for automated API testing. It started as an HTTP/HTTPS / SOAP-XML / JSON request runner with reporting and a JSON-driven executor, and now ships with a much wider toolkit — variable chaining, OpenAPI / Postman / HAR / cURL importers, a record-replay proxy, security probes, parallel runners, an MCP server for Claude, and more.
- Highlights
- Installation
- Quick Start
- Core Concepts
- Feature Map
- MCP Server for Claude
- Project Structure
- Optional Extras
- Development
- Contributing
- License
- Links
| Area | What you get |
|---|---|
| Backends | requests (sync, sessions), httpx (sync + async, HTTP/2), WebSocket, SSE, GraphQL |
| Data layer | Variable store, {{var}} templating, CSV/JSON data-driven loops, env profiles, fake data |
| Assertions | Field assertions, JSON Schema, JSONPath, snapshot, structural diffs, OpenAPI contract drift, response-time SLAs |
| Connection | mTLS, proxies, DNS override, VCR-style cassette record/replay |
| Mock server | Static, dynamic, stateful, fault injection, OpenAPI-driven, Jinja templating, webhook receiver, record-replay proxy |
| Runner | Sequential & parallel execution, tag filters, dependency-aware ordering, retry policies |
| Reports | HTML / JSON / XML / JUnit / Allure / Markdown / shields.io badge / SQLite trend store / run diff |
| Integrations | Slack / Teams / Discord webhook, GitHub PR comment, cURL & HAR importers, OpenAPI / Postman importer |
| CLI / DX | Subcommand CLI, REPL, terminal summary, shell completion, scaffold |
| Security | Auth helpers (Basic / Bearer / JWT / AWS SigV4), header / CORS / rate-limit / SSRF probes, pip-audit wrapper, fuzz inputs |
| Spec inference | Test record → OpenAPI, JSON Schema inference, OpenAPI changelog |
| AI | Pluggable backend with deterministic fallback for test generation, fake data, failure classification |
| MCP | First-class Claude Code / MCP server exposing the framework as tools |
| GUI | Optional PySide6 GUI (English / 繁中 / 简中 / 日本語) plus Swagger UI embed |
| Cross-platform | Windows, macOS, Linux. Python 3.10–3.14 |
pip install je_api_testkaOptional extras (install with pip install 'je_api_testka[<extra>]'):
| Extra | Adds |
|---|---|
gui |
PySide6 GUI |
websocket |
websockets for the WebSocket wrapper |
schema |
jsonschema and jsonpath-ng for advanced assertions |
security |
pyjwt and botocore for JWT / AWS SigV4 helpers |
otel |
opentelemetry-api / opentelemetry-sdk for tracing hooks |
mcp |
mcp Python SDK for the MCP server |
from je_api_testka import test_api_method_requests, generate_html_report
test_api_method_requests(
"get", "https://httpbin.org/get",
result_check_dict={"status_code": 200},
)
generate_html_report("smoke")JSON-driven equivalent (smoke.json):
{
"api_testka": [
["AT_test_api_method_requests", {
"http_method": "get",
"test_url": "https://httpbin.org/get",
"result_check_dict": {"status_code": 200}
}],
["AT_generate_html_report", {"html_file_name": "smoke"}]
]
}apitestka run smoke.json- Backends — every HTTP call goes through
requests_wrapper,httpx_wrapper,websocket_wrapper,sse_wrapper, orgraphql_wrapper. They share a record format. test_record_instance— a thread-safe singleton that captures every request / response. Reports, diffs, badges, and the trend store all read from it.- Executor — a command map (
AT_*keys) over Python callables. JSON action lists drive it. New features register themselves here soapitestka runcan use them without writing Python. - VariableStore — a thread-safe key/value store.
{{var}}placeholders inside payloads, URLs, headers, and templates resolve against it. Combine withAT_extract_and_storeto chain requests. - Optional dependencies — heavyweight features (WebSockets, JSON Schema, JWT, MCP) live behind extras and raise a friendly error if you call them without installing.
| Backend | Function |
|---|---|
requests |
test_api_method_requests (sync, sessions) |
httpx sync |
test_api_method_httpx |
httpx async |
test_api_method_httpx_async (HTTP/2 via http2=True) |
| WebSocket | test_api_method_websocket, test_api_method_websocket_async (extra: websocket) |
| SSE | iter_sse_events, test_api_method_sse |
| GraphQL | test_api_method_graphql, test_api_method_graphql_async |
from je_api_testka import test_api_method_graphql
test_api_method_graphql(
"https://api.example.invalid/graphql",
query="query Get($id: ID!) { user(id: $id) { id name } }",
variables={"id": "42"},
)from je_api_testka import (
variable_store, render_template, extract_and_store, load_env_profile,
fake_uuid, iter_csv_rows,
)
load_env_profile("envs/dev.json") # populates variable_store
extract_and_store({"data": {"id": 7}}, "data.id", "user_id")
render_template("/users/{{user_id}}") # -> "/users/7"
for row in iter_csv_rows("data/users.csv"):
variable_store.set("email", row["email"])
test_api_method_requests("post", "https://x.invalid/login", json=row)Executor commands: AT_set_variable, AT_get_variable, AT_clear_variables,
AT_extract_and_store, AT_render_template, AT_fake_uuid, AT_fake_email,
AT_fake_word, AT_load_env_profile.
from je_api_testka import (
check_json_schema, check_jsonpath, assert_snapshot,
diff_payloads, diff_openapi_specs, RetryPolicy, retry_call,
)
from je_api_testka.diff.sla_check import ResponseSLA, assert_sla
check_json_schema(payload, {"type": "object", "required": ["id"]})
check_jsonpath(payload, "$.data.id", expected=7)
assert_snapshot("user-by-id", payload, ignore_keys=["timestamp"])
diff = diff_payloads(prod_response, staging_response, ignore_paths=["server_time"])
assert_sla(records, ResponseSLA(max_ms=2000, p95_ms=1500))from je_api_testka.connection import (
ConnectionOptions, apply_to_requests_kwargs,
dns_override, Cassette, replay_or_record,
)
options = ConnectionOptions(cert=("c.crt", "c.key"),
proxies={"https": "http://proxy:8080"})
with dns_override({"api.example.invalid": "127.0.0.1"}):
test_api_method_requests("get", "https://api.example.invalid/health")
cassette = Cassette("tape.json") # offline replay-or-recordThe bundled FlaskMockServer now supports several layered features:
| Feature | API |
|---|---|
| Static routes | flask_mock_server_instance.add_router({...}) |
| Dynamic routes | server.add_dynamic_route(...) + DynamicRouter rules |
| Stateful store | server.state (StatefulStore) |
| Fault injection | server.fault_injector.configure(latency_seconds=..., failure_probability=...) |
| OpenAPI driven | server.load_openapi(spec) |
| Templated | server.add_template_route("/x", {"msg": "{{name}}"}) |
| Webhook receive | server.add_webhook("/hook") then read server.webhook_receiver.all() |
| Record-replay | server.add_proxy("https://upstream", "tape.json") |
apitestka mock --host 0.0.0.0 --port 9000from je_api_testka.runner import (
run_actions_parallel, filter_actions_by_tag, order_actions,
)
actions = order_actions(filter_actions_by_tag(actions, {"smoke"}))
results = run_actions_parallel(actions, max_workers=8)from je_api_testka import (
generate_html_report, generate_json_report, generate_xml_report,
)
from je_api_testka.utils.generate_report.junit_report import generate_junit_report
from je_api_testka.utils.generate_report.allure_report import generate_allure_report
from je_api_testka.utils.generate_report.markdown_report import generate_markdown_report
from je_api_testka.utils.generate_report.badge import generate_badge
from je_api_testka.utils.generate_report.run_diff import diff_runs
from je_api_testka.utils.generate_report.trend_store import record_current_run
generate_html_report("report")
generate_junit_report("junit.xml") # GitHub Actions / Jenkins
generate_allure_report("allure-results") # `allure generate` consumable
generate_markdown_report("report.md") # Slack / GitHub-friendly
generate_badge("badge.json") # shields.io endpoint
record_current_run("trend.sqlite") # historical trendOpenTelemetry hook (no-op when opentelemetry-api is absent):
from je_api_testka.utils.observability import instrument_request
with instrument_request("GET", "https://x.invalid"):
test_api_method_requests("get", "https://x.invalid")from je_api_testka.integrations import (
notify_via_webhook, post_pr_comment,
curl_to_action, convert_har,
)
from je_api_testka.cli.import_specs import convert_spec_file
notify_via_webhook("https://hooks.slack.invalid/...", summary="...", platform="slack")
post_pr_comment("acme/widget", pr_number=42, token="<gha-token>")
action = curl_to_action("curl -X POST https://api/x -d '{\"a\":1}'")
actions = convert_har("traffic.har")
actions = convert_spec_file("openapi.json", spec_format="openapi")apitestka run actions.json # or directory
apitestka create my_project
apitestka mock --port 9000
apitestka import openapi.json out.json --format openapi
apitestka repl # JSON action REPL
apitestka summary # ANSI-coloured summary
apitestka scaffold https://api/x out.json
apitestka completion bash # source >> ~/.bashrc
apitestka mcp # MCP server over stdiofrom je_api_testka.security import (
basic_auth_header, bearer_token_header, build_jwt, aws_sigv4_headers,
scan_security_headers, cors_preflight, probe_rate_limit, probe_ssrf,
fuzz_string_inputs, run_pip_audit,
)
scan_security_headers(response_headers) # HSTS, CSP, nosniff…
cors_preflight("https://api/x", origin="https://app")
probe_rate_limit("https://api/x", burst=20)
probe_ssrf("https://api/fetch", parameter="url")
run_pip_audit() # delegates to pip-auditfrom je_api_testka.spec import infer_schema, records_to_openapi, openapi_changelog
records_to_openapi(title="Recovered", version="0.1.0")
openapi_changelog(prev_spec, current_spec) # markdown diffpip install 'je_api_testka[gui]'Headless models (HistoryPanelModel, EnvManagerModel, render_side_by_side) live in
je_api_testka.gui, allowing tests and headless tooling to drive panels without
PySide6. The actual Qt widgets live in main_widget.py.
Locales: English, 繁體中文, 简体中文, 日本語. Switch via LanguageWrapper.reset_language(...).
Default backend (NoOpAIBackend) never calls a network. Plug in your own to enable
LLM-driven test generation:
from je_api_testka.ai import AIBackend, set_ai_backend, generate_tests_from_openapi
class AnthropicBackend(AIBackend):
def complete(self, prompt, *, context=None):
... # call your provider
return llm_response_text
set_ai_backend(AnthropicBackend())
actions = generate_tests_from_openapi(my_openapi_spec) # falls back to a deterministic
# happy path if the LLM reply is
# not valid JSONAPITestka ships an MCP server so Claude (and any other MCP-compatible client) can drive the framework. Eight tools are exposed:
| Tool | Purpose |
|---|---|
apitestka_run_action |
Execute an action list |
apitestka_test_api |
One-shot HTTP request via requests backend |
apitestka_curl_to_action |
cURL → action JSON |
apitestka_har_import |
HAR file → action list |
apitestka_render_markdown |
Markdown report from current records |
apitestka_records_to_openapi |
Reconstruct an OpenAPI document |
apitestka_clear_records |
Wipe the test record |
apitestka_get_records |
Return successes / failures |
Install and run:
pip install 'je_api_testka[mcp]'
apitestka-mcp # or: apitestka mcp / python -m je_api_testka.mcp_serverClaude Code config (~/.claude/mcp.json):
{
"mcpServers": {
"apitestka": {
"command": "apitestka-mcp"
}
}
}je_api_testka/
├── __init__.py # Public API exports
├── __main__.py # Legacy CLI entry point
├── ai/ # Pluggable AI backend + helpers
├── cli/ # apitestka CLI subcommands + REPL + completions
├── connection/ # ConnectionOptions, DNS override, Cassette
├── data/ # VariableStore, templates, faker, env profiles
├── diff/ # Response diff / contract drift / SLA
├── graphql_wrapper/ # GraphQL helper
├── gui/ # Optional PySide6 GUI + headless models
├── httpx_wrapper/ # httpx sync + async wrapper
├── integrations/ # Notifications, PR comments, importers
├── mcp_server/ # Claude / MCP server
├── pytest_plugin/ # pytest fixtures
├── requests_wrapper/ # requests wrapper
├── runner/ # Parallel runner, tag filter, dependency runner
├── security/ # Auth helpers, fuzz, header / CORS / SSRF / rate-limit / CVE
├── spec/ # OpenAPI inference / changelog
├── sse_wrapper/ # Server-Sent Events helper
├── utils/ # Executor, mock server, generators, etc.
└── websocket_wrapper/ # WebSocket wrapper
pip install 'je_api_testka[websocket]'
pip install 'je_api_testka[schema]'
pip install 'je_api_testka[security]'
pip install 'je_api_testka[otel]'
pip install 'je_api_testka[mcp]'
pip install 'je_api_testka[gui]'git clone https://github.com/Intergration-Automation-Testing/APITestka.git
cd APITestka
pip install -r dev_requirements.txt
pytest # full suite (~300+ tests)CI runs the suite against Python 3.10 – 3.14 on Ubuntu, macOS, and Windows.
See CONTRIBUTING.md. Every commit must ship with unit tests
(see CLAUDE.md → Testing Guidelines).
MIT — see licenses/APITestka_LICENSE.