API reference: servicewright.testing
In-memory doubles for testing services, entrypoints and containers. No dependencies, no extra.
See the testing guide for how they fit together.
In-memory test doubles for the servicewright kernel.
FakeSettings
Minimal settings double whose observability sections are all disabled.
Source code in servicewright/testing.py
| class FakeSettings:
"""Minimal settings double whose observability sections are all disabled."""
logging: Any = None
error_tracking: Any = None
tracing: Any = None
metrics: Any = None
def get_app_version(self) -> str:
"""Return a placeholder version."""
return "0.0.0-test"
|
get_app_version()
Return a placeholder version.
Source code in servicewright/testing.py
| def get_app_version(self) -> str:
"""Return a placeholder version."""
return "0.0.0-test"
|
FakeScope
In-memory scope whose get resolves from a provided mapping.
Source code in servicewright/testing.py
| class FakeScope:
"""In-memory scope whose ``get`` resolves from a provided mapping."""
def __init__(self, provides: Mapping[Any, Any] | None = None) -> None:
self._provides: dict[Any, Any] = dict(provides) if provides else {}
self.context: Mapping[Any, Any] | None = None
async def get(self, dependency_key: type[T] | str) -> Any:
"""Resolve a dependency or raise ``KeyError`` when absent."""
return self._provides[dependency_key]
|
get(dependency_key)
async
Resolve a dependency or raise KeyError when absent.
Source code in servicewright/testing.py
| async def get(self, dependency_key: type[T] | str) -> Any:
"""Resolve a dependency or raise ``KeyError`` when absent."""
return self._provides[dependency_key]
|
FakeContainer
In-memory :class:DependencyContainerProtocol for tests and users.
Source code in servicewright/testing.py
| class FakeContainer:
"""In-memory :class:`DependencyContainerProtocol` for tests and users."""
def __init__(self, provides: Mapping[Any, Any] | None = None) -> None:
self._provides: dict[Any, Any] = dict(provides) if provides else {}
self.app_scopes_opened = 0
self.unit_scopes_opened = 0
self.unit_contexts: list[Mapping[Any, Any] | None] = []
@contextlib.asynccontextmanager
async def app_scope(self) -> AsyncIterator[AppScopeProtocol]:
"""Yield a fresh application scope."""
self.app_scopes_opened += 1
yield FakeScope(self._provides)
@contextlib.asynccontextmanager
async def unit_scope(self, context: Mapping[Any, Any] | None = None) -> AsyncIterator[UnitScopeProtocol]:
"""Yield a fresh unit scope carrying ``context``."""
self.unit_scopes_opened += 1
self.unit_contexts.append(context)
scope = FakeScope(self._provides)
scope.context = context
yield scope
|
app_scope()
async
Yield a fresh application scope.
Source code in servicewright/testing.py
| @contextlib.asynccontextmanager
async def app_scope(self) -> AsyncIterator[AppScopeProtocol]:
"""Yield a fresh application scope."""
self.app_scopes_opened += 1
yield FakeScope(self._provides)
|
unit_scope(context=None)
async
Yield a fresh unit scope carrying context.
Source code in servicewright/testing.py
| @contextlib.asynccontextmanager
async def unit_scope(self, context: Mapping[Any, Any] | None = None) -> AsyncIterator[UnitScopeProtocol]:
"""Yield a fresh unit scope carrying ``context``."""
self.unit_scopes_opened += 1
self.unit_contexts.append(context)
scope = FakeScope(self._provides)
scope.context = context
yield scope
|
FakeEntrypoint
Bases: ScopedEntrypoint
Recording entrypoint that serves until stop is set.
Useful in tests to assert lifecycle ordering. Set run_once=True to
return immediately from serve (e.g. to model an essential exit).
Source code in servicewright/testing.py
| class FakeEntrypoint(ScopedEntrypoint):
"""Recording entrypoint that serves until ``stop`` is set.
Useful in tests to assert lifecycle ordering. Set ``run_once=True`` to
return immediately from ``serve`` (e.g. to model an essential exit).
"""
def __init__(
self,
*,
kind: str = "fake",
essential: bool = True,
run_once: bool = False,
) -> None:
super().__init__()
self.kind = kind
self.essential = essential
self._run_once = run_once
self.events: list[str] = []
async def bind(self, ctx: ServiceContext) -> None:
await super().bind(ctx)
self.events.append("bind")
async def serve(self, *, stop: asyncio.Event) -> None:
self.events.append("serve")
if self._run_once:
return
await stop.wait()
async def drain(self, grace: float) -> None:
self.events.append("drain")
async def stop(self) -> None:
self.events.append("stop")
|
unit_scope(context=None)
Open a per-unit-of-work DI scope.
Raises:
Source code in servicewright/core/contracts/bases.py
| def unit_scope(
self, context: Mapping[Any, Any] | None = None
) -> contextlib.AbstractAsyncContextManager[UnitScopeProtocol]:
"""Open a per-unit-of-work DI scope.
Raises:
RuntimeError: If called before :meth:`bind`.
"""
if self._container is None:
raise RuntimeError("unit_scope() called before bind(); entrypoint is not bound to a container")
return self._container.unit_scope(context)
|