Skip to content

Commit a0d178a

Browse files
committed
Better docs for testing conventions
1 parent 1b4ed8a commit a0d178a

2 files changed

Lines changed: 32 additions & 0 deletions

File tree

AGENTS.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ The project uses extremely strict mypy settings including `disallow_any_expr=tru
4949
**Testing Requirements:**
5050
All changes must maintain 100% branch coverage. Test both runtime and compiled behavior, plus async and thread-safe variants where applicable. Use descriptive test names: `test_<feature>_<scenario>_<expected_behavior>()`.
5151

52+
**Testing Conventions:**
53+
- **Compiled Objects**: Use `wired = execd["compiled"]` from `exec(code, execd)`. Do not instantiate `Compiled` manually.
54+
- **Type Safety**: Use `typing.Protocol` for dynamic/compiled objects. Avoid `Any` and `type: ignore`.
55+
- **Module Mocking**: Use `sys.modules` injection with `try...finally` cleanup for custom classes.
56+
- **Async Tests**: Use `asyncio.run()` explicitly within test functions.
57+
5258
**Common Gotchas:**
5359
- SPDX headers required on all files (run `make format` to auto-add)
5460
- 79-character line limit enforced by `black`

docs/development.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,32 @@ pytest -xvs
4949

5050
The project enforces 95% test coverage or higher. New code should include comprehensive tests.
5151

52+
#### Testing Conventions
53+
54+
- **Compiled Code Testing**: When testing compiled code, use the pre-instantiated `compiled` object from the execution namespace instead of manually instantiating the class.
55+
```python
56+
exec(code, execd)
57+
wired = execd["compiled"] # Use this instance
58+
```
59+
- **Type Safety in Tests**: Avoid `Any` and `type: ignore`. Use `typing.Protocol` to define the expected interface of dynamic or compiled objects.
60+
```python
61+
class MockConfig(Protocol):
62+
def config(self) -> Config: ...
63+
64+
execd: dict[str, MockConfig] = {}
65+
```
66+
- **Coverage**: Aim for 100% branch coverage.
67+
- **Naming**: Use descriptive test names: `test_<feature>_<scenario>_<expected_behavior>()`.
68+
- **Module Mocking**: When testing custom classes, inject them into `sys.modules` using a `try...finally` block to ensure cleanup.
69+
```python
70+
class MockModule(ModuleType): ...
71+
sys.modules["mymod"] = MockModule()
72+
try:
73+
# test code
74+
finally:
75+
del sys.modules["mymod"]
76+
```
77+
5278
### Code Formatting
5379

5480
The project uses `black` and `isort` for code formatting:

0 commit comments

Comments
 (0)