Skip to main content

quadkit-testing

Quadkit

PyPI Python License

Test harnesses, fakes, and fixtures for Quadkit applications: boot the real application in-process, substitute bindings instead of mocking import sites, and assert on responses with helpers that say what failed.

For anyone writing tests against Quadkit applications — and for tooling that needs drop-in implementations of the framework's protocols.

The quadkit family

Package Role
quadkit-contracts zero-dependency protocols, types, exception hierarchy
quadkit the framework core — DI container, modules, config, logging, Result
quadkit-web ASGI layer — controllers, routing, middleware, OpenAPI docs
quadkit-cli project scaffolding and code generators
quadkit-testing in-process test beds, fakes, fixtures

Installation

uv add --dev quadkit-testing

Requires Python >= 3.11.

Minimal working example

Test an HTTP route with the real application, in-process:

import pytest

from quadkit.testing import WebTestBed

from my_app import create_app


@pytest.mark.asyncio
async def test_hello() -> None:
    async with WebTestBed(create_app()) as bed:
        response = bed.get("/hello", params={"name": "quadkit"})
        response.assert_status(200)
        assert response.json == {"message": "hello, quadkit"}

Or test services directly, with binding overrides:

async def test_service() -> None:
    from quadkit.testing import AppTestBed

    async with AppTestBed.from_factory(
        create_app, overrides={Cache: FakeCache()}
    ) as bed:
        service = await bed.app.container.resolve(UserService)

A pytest plugin registers automatically via entry points — no conftest.py wiring — and provides auto-registered fixtures including fake_cache, fake_event_bus, fake_logger, fake_clock, fake_command_bus, fake_query_bus, fake_unit_of_work, fake_metrics, fake_config, fake_state_store, test_bed, test_container, and test_data:

import pytest

from quadkit.contracts.domain.events import DomainEvent


class UserCreated(DomainEvent):
    user_id: str
    email: str


@pytest.mark.asyncio
async def test_signup_publishes(fake_event_bus) -> None:
    await fake_event_bus.publish(UserCreated(user_id="1", email="a@b.c"))
    fake_event_bus.assert_published(UserCreated, user_id="1")


def test_trial_expiry_is_deterministic(fake_clock) -> None:
    t0 = fake_clock.now()
    fake_clock.advance(30 * 24 * 3600)
    assert (fake_clock.now() - t0).days == 30

Optional extras

Extra Contents
[web] httpx + Starlette — the WebTestBed client transport
[db] aiosqlite, asyncpg — drivers for your async DB test suites
[integration] service clients for integration suites (Redis, MongoDB, Kafka, Elasticsearch, Neo4j, Qdrant, PostgreSQL, SQLite)
[dev] ruff, mypy, black

Public API entry points

Test beds

from quadkit.testing import AppTestBed, WebTestBed
  • AppTestBed.from_factory(factory, overrides=None) / AppTestBed.from_app(app) — application-level beds.
  • WebTestBed(app_or_provider, raise_server_exceptions=True) with get/post/put/patch/delete, override(Contract, impl) (before boot), and TestResponse — status_code, headers, text, json (property), assert_status, assert_json, assert_json_path, assert_header.
  • quadkit.testing.fixtures.container.ContainerTestFixture — DI-level fixture with mock(), override(), get(), get_optional().
  • quadkit.testing.fixtures.bed.TestEnvironment — programmatic environment builder (use_provider, override, fake, resolve).
  • quadkit.testing.lib.factory.TestDataFactory — deterministic create_user(), create_task(), create_message(), create_request().

Fakes (quadkit.testing.fakes)

All in-process, async-native, implementing the same contracts as the real services:

Class Covers
FakeCache / FakeStateStore cache and state storage
FakeEventBus in-process events with assert_published(), published_of_type(), assert_events_in_order() and friends
FakeCommandBus / FakeQueryBus command / query dispatch
FakeUnitOfWork unit-of-work context
FakeClock (+ Clock, SystemClock) deterministic time
FakeConfig config overrides
FakeLogger (+ LogEntry) structlog-compatible sink
FakeMetricsCollector / FakeResourceUnitTracker metrics / resource tracking
FakeRedisClient Redis-protocol client
FakeAuditLogger audit records
FakeTracer / FakeSpan tracing

The published wheel carries the ai, db and web test clients and beds plus the fakes and fixtures that need no private package. The auth, cache, events, search, storage, tasks, ui test clients, the AI/DB/task fixture modules, the secrets fake and IntegrationEnvironment stay in this repository until their packages publish; asking the published wheel for one raises AttributeError naming the module.

Configuration

None required — the pytest plugin self-registers. Mark suites for external services and gate them yourself (e.g. uv run pytest -m "not integration").

Error handling

Test beds surface failures, they don't hide them: with raise_server_exceptions=True (the default) unexpected exceptions re-raise into your test with their original traceback; HTTP-expected failures assert on the response instead.

Testing

Ironically self-hosted: this package's public tests are among the suite the release executes from the exported tree against the built wheels.

Security

Fakes are in-process and safe to wire into unit suites. Report vulnerabilities privately per SECURITY.md.

Stability

Version 0.0.3 in the 0.x series, released in lockstep with the other four distributions; APIs may change between minor versions until 1.0 — pin an exact version (quadkit-testing==0.0.3) or a tight range (>=0.0.3,<0.1.0). Full policy: stability and compatibility.

Apache-2.0 — see LICENSE. "Quadkit" and the Quadkit logo are trademarks of the project — see TRADEMARK.md.

Release files for quadkit-testing 0.0.41

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for quadkit-testing 0.0.41
File Size Uploaded
quadkit_testing-0.0.41.tar.gz 190.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for quadkit-testing 0.0.41
File Interpreter ABI Platform
quadkit_testing-0.0.41-py3-none-any.whl Python 3 none any Details

Total release size: 357.8 kB

Release files / quadkit_testing-0.0.41.tar.gz

Download URL quadkit_testing-0.0.41.tar.gz
Size 190.7 kB
Tags Source
SHA-256 checksum
How to use checksums
822749047fd9ea3d257c81615593311c0c41a1cef32221153b2bfc3e4c8be983
BLAKE2b-256 checksum
How to use checksums
90f6ea46c3d201761fbf167390b46bf09097c3256113693ce267e02da50cb8b7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.8.14

Release files / quadkit_testing-0.0.41-py3-none-any.whl

Download URL quadkit_testing-0.0.41-py3-none-any.whl
Size 167.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a6945efa15f8d57ae40c9ca5a57df2d9e905e3cb784d9c510393328378f726fd
BLAKE2b-256 checksum
How to use checksums
c7f8a9c6df9bfe8327a587bbbafed0d83e58f80f17a1fc8b90ff05ede06b22fa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.8.14

Release history Release notifications | RSS feed

0.0.42

2 release files

This release

0.0.41 This release

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page