Merge pull request '[AUTO-INF-3] Consolidate Behave database fixtures via shared factory' (#9596) from auto-inf-3-consolidate-behave-fixtures into master
CI / benchmark-regression (push) Has started running
CI / push-validation (push) Successful in 33s
CI / lint (push) Successful in 39s
CI / build (push) Successful in 37s
CI / helm (push) Successful in 40s
CI / e2e_tests (push) Successful in 1m1s
CI / quality (push) Successful in 1m12s
CI / typecheck (push) Successful in 1m21s
CI / security (push) Successful in 1m21s
CI / unit_tests (push) Successful in 5m0s
CI / docker (push) Successful in 1m41s
CI / integration_tests (push) Successful in 8m32s
CI / coverage (push) Successful in 9m2s
CI / status-check (push) Successful in 3s
CI / benchmark-publish (push) Failing after 24m17s

This commit was merged in pull request #9596.
This commit is contained in:
2026-06-03 12:39:55 +00:00
committed by Forgejo
2 changed files with 91 additions and 0 deletions
+8
View File
@@ -824,3 +824,11 @@ def after_scenario(context, scenario):
# Scenario.run() wrapper installed in _install_tdd_expected_fail_patch(),
# NOT in this hook. See before_all() and CONTRIBUTING.md > TDD Issue
# Test Tags for the full specification.
# Clean up test UnitOfWork fixtures if any were created
try:
from features.mocks.test_uow_factory import cleanup_test_uow
cleanup_test_uow(context)
except ImportError:
pass
+83
View File
@@ -9,13 +9,22 @@ both test suites exercise the same database setup. Any changes to
``UnitOfWork.__init__`` must be reflected here in a single place rather
than in each consuming test file.
Behave Context Adapters:
- ``use_test_uow(context)`` — Attach a test UoW to a Behave context and
register engine cleanup on scenario teardown.
Used by:
- ``features/steps/plan_use_action_args_integrity_steps.py``
- ``features/steps/plan_service_steps.py``
- ``features/steps/project_cli_steps.py``
- ``features/steps/project_service_coverage_boost_steps.py``
- ``robot/helper_plan_use_action_args_integrity.py``
"""
from __future__ import annotations
import contextlib
from collections.abc import Callable
from typing import Any
from sqlalchemy import create_engine, event
@@ -69,3 +78,77 @@ def build_test_uow() -> tuple[UnitOfWork, sessionmaker[Session], Engine]:
uow._require_confirmation = False
return uow, sf, engine
def use_test_uow(
context: Any,
seed_hook: Callable[[UnitOfWork], None] | None = None,
) -> UnitOfWork:
"""Attach a test UnitOfWork to a Behave context with automatic cleanup.
This is the recommended way to set up database fixtures in Behave step
definitions. It ensures:
- Consistent in-memory SQLite configuration across all tests
- Foreign key PRAGMA enforcement
- Automatic engine cleanup on scenario teardown
- Optional seed hook for test data setup
Args:
context: The Behave context object (typically from a step function).
seed_hook: Optional callable that receives the UoW and populates
test data. Called immediately after UoW creation.
Returns:
The configured UnitOfWork instance, also attached to context.uow.
Example:
@given("a plan service with test database")
def step_plan_service_with_test_db(context):
uow = use_test_uow(context)
context.plan_service = PlanService(uow)
"""
uow, sf, engine = build_test_uow()
# Attach to context for use in step definitions
context.uow = uow
context.session_factory = sf
context.engine = engine
# Register cleanup callback
def cleanup_engine() -> None:
"""Dispose of the engine connection pool."""
engine.dispose()
# Store cleanup function for later invocation
if not hasattr(context, "_cleanup_callbacks"):
context._cleanup_callbacks = []
context._cleanup_callbacks.append(cleanup_engine)
# Run optional seed hook
if seed_hook is not None:
seed_hook(uow)
return uow
def cleanup_test_uow(context: Any) -> None:
"""Clean up test UnitOfWork resources attached to a Behave context.
This should be called in an ``after_scenario`` hook or similar teardown.
Args:
context: The Behave context object.
"""
if hasattr(context, "_cleanup_callbacks"):
for callback in context._cleanup_callbacks:
with contextlib.suppress(Exception):
callback()
context._cleanup_callbacks.clear()
# Clear references
if hasattr(context, "uow"):
delattr(context, "uow")
if hasattr(context, "session_factory"):
delattr(context, "session_factory")
if hasattr(context, "engine"):
delattr(context, "engine")