Requests Automation Framework
Project description
APITestka
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.
Table of Contents
- Highlights
- Installation
- Quick Start
- Core Concepts
- Feature Map
- MCP Server for Claude
- Project Structure
- Optional Extras
- Development
- Contributing
- License
- Links
Highlights
| 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 |
Installation
pip install je_api_testka
Optional 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 |
Quick Start
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
Core Concepts
- 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.
Feature Map
HTTP / Protocol Backends
| 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"},
)
Data Layer
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.
Assertions, Diffs and SLAs
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))
Connection Layer
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-record
Mock Server
The 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 9000
Runner
from 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)
Reports and Observability
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 trend
OpenTelemetry 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")
Integrations
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")
CLI / Developer Experience
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 stdio
Security Probes
from 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-audit
OpenAPI Inference
from 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 diff
GUI
pip 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(...).
Pluggable AI Backend
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 JSON
MCP Server for Claude
APITestka 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_server
Claude Code config (~/.claude/mcp.json):
{
"mcpServers": {
"apitestka": {
"command": "apitestka-mcp"
}
}
}
Project Structure
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
Optional Extras
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]'
Development
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.
Contributing
See CONTRIBUTING.md. Every commit must ship with unit tests
(see CLAUDE.md → Testing Guidelines).
License
MIT — see licenses/APITestka_LICENSE.
Links
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file je_api_testka-0.0.140.tar.gz.
File metadata
- Download URL: je_api_testka-0.0.140.tar.gz
- Upload date:
- Size: 102.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f949a476be85ef590789d2368402cabc3d21df35e26b5f2898acc5811593f0dd
|
|
| MD5 |
0a1417aca1a31979f71622c6652be9ae
|
|
| BLAKE2b-256 |
1d3aaac9dc900b2a06e5d66fed72178dde3d2692cbda1dbf8bb93752d40808df
|
File details
Details for the file je_api_testka-0.0.140-py3-none-any.whl.
File metadata
- Download URL: je_api_testka-0.0.140-py3-none-any.whl
- Upload date:
- Size: 142.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
89f777f4df8da5f082a5e3e1c735984d179f318ae034688d99253c30befbba8d
|
|
| MD5 |
dcc47ff69f5a532d391a0f55ed6ed2c4
|
|
| BLAKE2b-256 |
0927cc299bd2785e95a922ef53c98c61db14c8d2cc738a4885e331821144c9ff
|