You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
refactor: update BDD testing documentation and enhance async step implementations
- Clarified the usage of the Behave BDD framework, specifying version 1.3.3.
- Added details on the directory structure for BDD tests, including new files for global setup and shared utilities.
- Updated async step implementations to use `await` instead of `asyncio.run()`, ensuring proper async handling.
- Removed deprecated utility functions from `test_helpers.py` to streamline the codebase.
- Adjusted linting exclusions and documentation for better clarity and organization.
- Step redefinition (`F811`) is allowed — Behave reuses steps across features.
55
-
- Use `context` to share state between steps within a scenario.
56
-
57
-
```python
58
-
# ✅ GOOD
59
-
from behave import given, then, when
50
+
- Use `get_current_scenario_context(context)` to share state between steps.
60
51
61
-
@given("a running Redis instance")
62
-
def step_redis_running(context):
63
-
context.redis = FakeRedisAdapter()
52
+
## Async Steps
64
53
65
-
@when('I store "{value}" under key "{key}"')
66
-
def step_store_value(context, value, key):
67
-
context.redis.set(key, value)
54
+
Behave 1.3.3 supports `async def` step functions **natively** — no `asyncio.run()` or `@async_run_until_complete` wrapper needed. Always declare async steps with `async def` and use `await` directly.
68
55
69
-
@then('I can retrieve "{value}" from key "{key}"')
70
-
def step_retrieve_value(context, value, key):
71
-
assert context.redis.get(key) == value
56
+
```python
57
+
# ❌ BAD — never use asyncio.run() inside a step
58
+
@when("something async happens")
59
+
def step_impl(context):
60
+
result = asyncio.run(some_async_call())
61
+
62
+
# ✅ GOOD — declare the step as async def and await directly
63
+
@when("something async happens")
64
+
async def step_impl(context):
65
+
result = await some_async_call()
72
66
```
73
67
68
+
Sync operations work fine inside `async def` steps, so steps with mixed sync/async branches (e.g. if/elif over frameworks) should be converted to `async def` entirely.
69
+
70
+
The only place `asyncio.run()` is acceptable is in **non-step** callbacks (e.g. `scenario_context.py` cleanup methods) that may be called from outside an event loop.
71
+
74
72
## Parallel Execution
75
73
76
-
Behave is configured to run with **8 parallel workers** (multiprocessing). Ensure steps do not share mutable global state across scenarios.
74
+
Behave is configured to run with **8 parallel workers** (multiprocessing). Steps must not share mutable global state across scenarios.
77
75
78
76
## Linting Exclusions
79
77
80
-
`features/` and `scripts/` directories are excluded from Ruff linting (`exclude` in `pyproject.toml`). Do not add type annotations to step functions.
78
+
`features/` and `scripts/` are excluded from Ruff linting. Do not add type annotations to step functions.
0 commit comments