Qx testing helpers: testcontainers, fixtures, mediator/repository doubles, outbox assertions
Project description
qx-testing
Testing helpers for Qx services — testcontainers, mediator and repository doubles, outbox assertions, and pytest fixture factories.
What lives here
qx.testing.postgres_container/redis_container/nats_container— context managers that start Docker containers via testcontainers. Each yields the running container with aget_connection_url()or equivalent accessor. Docker Desktop on macOS is detected automatically via~/.docker/run/docker.sock.qx.testing.MediatorStub— in-memoryMediatorreplacement. Pre-register handler return values withstub.on(CommandType, result). Asserts that each stubbed command was sent exactly once.qx.testing.RepositoryStub— in-memoryRepository[TEntity]backed by a plaindict. Supportsadd,get,list,save, andsoft_delete. No database required.qx.testing.OutboxAssert— queries the realqx_outbox_eventstable and providesassert_event_published(event_name, where={...}). Used in integration tests to verify that the transactional outbox was populated correctly.qx.testing.container_factory— pytest fixture that builds and tears down a DIContainerwith all singletons initialized.qx.testing.mediator_factory— pytest fixture that creates aMediatorwired to a test container.qx.testing.http_client_factory— pytest fixture that wraps a FastAPI app in aTestClientwith a fresh Prometheus registry per test.
Usage
Integration test with a real Postgres container
import pytest
from qx.testing.containers import postgres_container
from qx.testing.assertions import OutboxAssert
@pytest.fixture(scope="session")
def db_url():
with postgres_container() as pg:
yield pg.get_connection_url()
def test_create_user_writes_outbox(client, outbox: OutboxAssert):
client.post("/v1/users", json={"email": "a@b.com", "name": "Ada"})
import asyncio
asyncio.run(
outbox.assert_event_published(
"identity.user.registered",
where={"email": "a@b.com"},
)
)
Unit test with doubles
from qx.testing import MediatorStub, RepositoryStub
from qx.core import Result
async def test_create_user_handler():
users = RepositoryStub(User)
uow = FakeUnitOfWork(users)
handler = CreateUserHandler(uow)
result = await handler.handle(CreateUserCommand(email="a@b.com", name="Ada"))
assert result.is_success
assert len(users.all()) == 1
Design rules
- Use
NullPoolfor all test engines that callasyncio.run()in fixtures — asyncpg connections are bound to the event loop that created them and cannot be reused acrossasyncio.run()boundaries. RepositoryStubraises the sameNotFoundError/ConflictErrorshapes as the real repository so handler tests exercise error paths without a database.MediatorStub.assert_all_sent()can be called inteardownto catch unexpected commands that were sent but not stubbed.
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
qx_testing-1.0.1.tar.gz
(8.5 kB
view details)
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 qx_testing-1.0.1.tar.gz.
File metadata
- Download URL: qx_testing-1.0.1.tar.gz
- Upload date:
- Size: 8.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5839e5edc57b18d7456be0c4c081b128b737e603c36029a01446de064942d65a
|
|
| MD5 |
93cb81847173e60680a3c61defae4cce
|
|
| BLAKE2b-256 |
f85586e4a9220f54be8d488bdf5791ff1644898869ded35152ff51be2193d521
|
File details
Details for the file qx_testing-1.0.1-py3-none-any.whl.
File metadata
- Download URL: qx_testing-1.0.1-py3-none-any.whl
- Upload date:
- Size: 9.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0a2b2e881b6e127a35e97d99784f050852c664d9d5552dcdd02c33dd157b0128
|
|
| MD5 |
32115f47ace2ea331bb96f6c1d78e77e
|
|
| BLAKE2b-256 |
c9215ffe89f96772b17e96c6f24ad4dcde437f23268f879107c1f5186bb49218
|