APITestka (je_api_testka) is a lightweight, cross-platform Python framework for automated API testing. Supports HTTP/HTTPS, SOAP/XML, JSON with requests and httpx backends.
- Python: 3.10+
- Dependencies:
requests,Flask,httpx - Optional GUI:
PySide6==6.11.0,qt-material
pip install -e . # Install in development mode
pip install -e .[gui] # Install with GUI support
pytest # Run all tests
pytest test/test_requests/ # Run requests backend tests only
pytest test/test_httpx_sync/ # Run httpx sync tests only
pytest test/test_httpx_async/ # Run httpx async tests only
pytest test/test_utils/ # Run utility tests only
pytest -x # Stop on first failure- Test config:
pyproject.toml([tool.pytest.ini_options],testpaths = ["test"],asyncio_mode = "auto") - Root
conftest.pyfilters out source files from collection
je_api_testka/
├── requests_wrapper/ # Facade pattern - wraps requests library
├── httpx_wrapper/ # Facade pattern - wraps httpx (sync + async)
├── utils/
│ ├── assert_result/ # Strategy pattern - response validation
│ ├── callback/ # Observer pattern - post-request callbacks
│ ├── executor/ # Command pattern - JSON keyword-driven actions
│ ├── generate_report/ # Template Method - HTML/JSON/XML reports
│ ├── mock_server/ # Flask-based mock server
│ ├── socket_server/ # TCP remote automation server
│ ├── project/ # Factory pattern - project scaffolding
│ ├── json/ # JSON I/O utilities
│ ├── xml/ # XML parse/convert utilities
│ ├── test_record/ # Singleton - global test record storage
│ ├── logging/ # Singleton - logging instance
│ ├── file_process/ # File listing utilities
│ ├── package_manager/ # Plugin pattern - dynamic package loading
│ └── exception/ # Custom exception hierarchy
└── gui/ # Optional PySide6 GUI
- Facade Pattern:
requests_wrapperandhttpx_wrapperprovide unified interfaces over HTTP libraries - Command Pattern: Executor maps string commands to callable functions, enabling JSON-driven test scripting
- Singleton Pattern:
test_record_instanceand logging are shared global instances - Strategy Pattern: Assertion checks are decoupled from request execution
- Observer/Callback Pattern:
callback_executorhooks into test completion events
- Never hardcode credentials, tokens, API keys, or secrets in source code
- Always validate and sanitize all external input (user input, network data, file content)
- Prevent injection: parameterize queries, escape XML/HTML output, validate URLs before requests
- Use
defusedxmlor equivalent safe parsers for XML input to prevent XXE attacks - Socket server: validate all incoming commands; reject malformed or unauthorized payloads
- No
eval()orexec()on untrusted input; executor command mapping must use explicit allowlists - Dependency awareness: keep
requests,Flask,httpxupdated; audit for known CVEs - File operations: validate paths to prevent directory traversal; never trust user-supplied file paths without sanitization
- Connection reuse: use session-based requests (
session_get, etc.) for repeated calls to the same host - Async by default: prefer
httpxasync backend for high-concurrency workloads - HTTP/2: enable
http2=Truefor multiplexed connections where supported - Lazy imports: defer heavy imports (PySide6, optional dependencies) until actually needed
- Minimize allocations: reuse buffers and avoid unnecessary copies in hot paths (report generation, record storage)
- Thread safety:
test_record_instancemust be thread-safe when used in concurrent test execution
- Single Responsibility: each module handles one concern; do not mix request logic with reporting
- Open/Closed Principle: extend executor via
add_command_to_executorinstead of modifying core command map - DRY: shared logic (response parsing, record formatting) must live in utility modules, not duplicated across wrappers
- Fail fast: raise specific exceptions (
APIAssertException, custom errors) immediately on validation failures - Type hints: all public API functions must have type annotations
- Docstrings: public functions require docstrings; internal helpers need them only when logic is non-obvious
- Follow PEP 8
- Use snake_case for functions and variables, PascalCase for classes
- Prefix internal/private helpers with underscore (
_helper_func) - Keep functions focused and short; extract logic into helpers when a function exceeds ~50 lines
- No unused imports, variables, or dead code blocks - remove them immediately
All code must pass static analysis without warnings from SonarQube, Codacy, Pylint, Flake8, and Bandit. Adhere to the following rules:
- No bare
except:clauses — always catch specific exception types (except ValueError:), neverexcept:orexcept Exception:without re-raise/log (S5754, E722) - No mutable default arguments — use
Noneas default and assign inside the function (e.g.,def f(x=None): x = x or []) (W0102) - Always close resources — use
withcontext managers for files, sockets, sessions; never rely on garbage collection (S2095, R1732) - No unreachable code — remove statements after
return,raise,break,continue(S1763, W0101) - No identical branches in
if/elif/else— collapse duplicates (S1871) - No assignment in conditions —
if x = func():is forbidden; assign first (S1656) - Comparisons must not always be true/false — avoid
if x is None and x == 5:patterns (S2589) - Use
is/is notforNone,True,False— never== None(E711) - No self-comparison —
if x == x:is a bug (S1764) - Loop variables must be used — if unused, name them
_(W0612)
- No
pickle.loads()on untrusted input — use JSON instead (B301) - No
subprocesswithshell=True— pass arg list (B602, S4721) - No
randommodule for security — usesecretsmodule for tokens/keys (B311, S2245) - No hardcoded
0.0.0.0bindings without explicit comment justifying it (B104) - No
assertfor runtime validation — assertions are stripped with-O; raise exceptions instead (B101) - No
tempfile.mktemp()— useNamedTemporaryFileormkstemp()(B306) - No
requestscalls without timeout — always passtimeout=(S4502) - No
verify=Falseon TLS connections without explicit justification comment (B501) - SQL/XPath/LDAP must be parameterized — never f-string user input into queries (S3649)
- Cognitive complexity ≤ 15 per function — refactor nested loops/conditions into helpers (S3776)
- Cyclomatic complexity ≤ 10 (C901)
- Function parameters ≤ 7 — group related params into a dataclass/dict (S107, R0913)
- Function length ≤ 50 lines of code excluding docstrings (R0915)
- File length ≤ 500 lines — split large modules (C0302)
- Class methods ≤ 20 — split large classes (R0904)
- Nesting depth ≤ 4 levels (S134)
- No duplicate string literals appearing 3+ times — extract to a module-level constant (S1192)
- No duplicate code blocks ≥ 6 lines — extract to a function (common-duplicate)
- Boolean parameters discouraged — prefer enums or two named functions (S2301)
- Module names:
lower_snake_case, no hyphens (C0103) - Constants:
UPPER_SNAKE_CASE(C0103) - Class names:
PascalCasewith no underscores (C0103) - Avoid single-letter variable names outside short loops/comprehensions (
i,j,kok;x,ynot for business logic) - Line length ≤ 120 characters (E501)
- Two blank lines between top-level functions/classes, one between methods (E302, E305)
- No trailing whitespace, no tabs (W291, W191) — use 4 spaces
- Imports order: stdlib → third-party → local, separated by blank lines, alphabetized (I100, I201)
- No wildcard imports (
from x import *) outside__init__.py(F403, W0401)
- No
TODO/FIXMEwithout an issue link —# TODO(#123): description(S1135) - No commented-out code — delete it; git preserves history (S125)
- No
print()in library code — use theloggingmodule (T201) - No magic numbers — extract to named constants (e.g.,
DEFAULT_TIMEOUT_SECONDS = 30) (R2004) - Functions returning
Noneshould not have explicitreturn None(R1711) - Use f-strings, not
%or.format()for new code (UP032) - Use
pathlib.Pathinstead ofos.pathfor new code where possible (PTH) - Avoid
len(x) == 0— usenot xfor empty containers (C1801)
- All public functions need type hints on parameters and return types (mypy strict)
- No
Anyin public APIs — useTypeVar,Protocol, or concrete types - Use
Optional[T](orT | None) explicitly; never imply nullability
- Test functions may exceed cognitive complexity for table-driven assertions
assertis allowed and expected in test files- Magic numbers are acceptable in test fixtures
- Every new feature, fix, or refactor MUST ship with unit tests in the same commit.
- New module → add a corresponding
test/test_<area>/test_<module>.py. - Bug fix → add a regression test that fails before the fix and passes after.
- Refactor → existing tests must still pass; add coverage for any newly-exposed branches.
- New module → add a corresponding
- Place tests under the matching subdirectory (
test/test_utils/,test/test_requests/, etc.); create new subpackages with a__init__.pywhen introducing a fresh area. - Tests for optional-dependency modules (e.g.
websockets,jsonschema) must:- Skip gracefully via
pytest.importorskip("<package>")when the dep is missing, AND - Cover the "dependency missing" error path by monkeypatching the import to raise
ImportError.
- Skip gracefully via
- Use the existing fixtures in
test/conftest.py(mock_url,clean_test_records,assert_valid_response,run_report_suite) rather than rolling new ones. - Run
pytest -xlocally before committing; CI runs the full matrix on Python 3.10–3.14. - A commit that introduces production code without tests is incomplete and should not be pushed.
- Write commit messages in English
- Use conventional format:
type: short description- Types:
feat,fix,refactor,test,docs,chore,perf,security
- Types:
- Do NOT mention any AI tools, assistants, or co-authors in commit messages
- No
Co-Authored-Bylines referencing AI in commits - Focus on what changed and why, not how it was written
- Examples:
feat: add HTTP/2 multiplexing support for httpx async backendfix: prevent XXE injection in XML report parserrefactor: extract common response parsing to shared utilitysecurity: sanitize socket server input against command injection
- Define the function in the appropriate module
- Register via
add_command_to_executor({"COMMAND_NAME": func}) - Prefix command names with
AT_to follow existing convention - Add corresponding tests in
test/test_utils/
- Create module in
je_api_testka/utils/generate_report/ - Follow the Template Method pattern used by existing report generators
- Register in
__init__.pypublic API exports - Add tests validating output format and edge cases
- Define endpoint function with proper request validation
- Register via
flask_mock_server_instance.add_router() - Always validate input parameters in mock endpoints