Skip to content

Commit 6ab38cc

Browse files
committed
refactor: Reorganize async tests into tests/asyncio/ directory
Moved all async-specific tests into tests/asyncio/ following CPython's organization pattern. Added comprehensive README.md with testing guidelines, fixture documentation, and best practices. Structure: - test_basic.py (was test_async.py) - Basic async functionality - test_acmd.py (was test_async_acmd.py) - Pattern A tests (8 tests) - test_tmux_cmd.py (was test_async_tmux_cmd.py) - Pattern B tests (9 tests) - test_hybrid.py (was test_async_hybrid.py) - Both patterns tests (7 tests) - test_docstring_examples.py - Docstring verification tests (11 tests) - README.md - Comprehensive testing guide with examples - __init__.py - Package marker Benefits: - Clear separation of async tests - Follows CPython's organizational patterns - Comprehensive documentation for contributors - Easy to run all async tests: pytest tests/asyncio/ Verified with: pytest tests/asyncio/ -v Result: 37 passed in 1.20s (36 tests + 1 README doctest)
1 parent 9767317 commit 6ab38cc

File tree

7 files changed

+180
-0
lines changed

7 files changed

+180
-0
lines changed

tests/asyncio/README.md

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
# Async Tests for libtmux
2+
3+
This directory contains all async-specific tests for libtmux's async support.
4+
5+
## Structure
6+
7+
```
8+
tests/asyncio/
9+
├── README.md # This file
10+
├── test_basic.py # Basic async functionality tests
11+
├── test_acmd.py # Pattern A (.acmd() methods) tests
12+
├── test_tmux_cmd.py # Pattern B (tmux_cmd_async) tests
13+
├── test_hybrid.py # Tests for both patterns working together
14+
└── test_docstring_examples.py # Verification tests for docstring examples
15+
```
16+
17+
## Test Organization
18+
19+
### test_basic.py
20+
Basic async functionality tests:
21+
- Async command execution
22+
- Event loop integration
23+
- Basic async/await patterns
24+
25+
### test_acmd.py (Pattern A)
26+
Tests for `.acmd()` methods on Server/Session/Window/Pane objects:
27+
- `server.acmd()` execution
28+
- Object-oriented async operations
29+
- Gradual migration from sync to async patterns
30+
31+
### test_tmux_cmd.py (Pattern B)
32+
Tests for direct `tmux_cmd_async()` execution:
33+
- Direct async command execution
34+
- Socket isolation with `-L` flag
35+
- Async-first architecture patterns
36+
37+
### test_hybrid.py
38+
Tests for using both patterns together:
39+
- Pattern A and Pattern B in same codebase
40+
- Concurrent execution across patterns
41+
- Integration scenarios
42+
43+
### test_docstring_examples.py
44+
Verification tests for all docstring examples:
45+
- Ensures all code examples in docstrings actually work
46+
- Tests examples from src/libtmux/common_async.py
47+
- Tests examples from docs/quickstart_async.md
48+
- Tests examples from docs/topics/async_programming.md
49+
50+
## Running Tests
51+
52+
Run all async tests:
53+
```bash
54+
pytest tests/asyncio/ -v
55+
```
56+
57+
Run specific test file:
58+
```bash
59+
pytest tests/asyncio/test_acmd.py -v
60+
```
61+
62+
Run with coverage:
63+
```bash
64+
pytest tests/asyncio/ --cov=libtmux.common_async --cov-report=term-missing
65+
```
66+
67+
## Test Requirements
68+
69+
All async tests must:
70+
71+
1. **Use pytest-asyncio**: Mark test functions with `@pytest.mark.asyncio`
72+
```python
73+
@pytest.mark.asyncio
74+
async def test_something(async_server):
75+
result = await async_server.acmd('list-sessions')
76+
assert result is not None
77+
```
78+
79+
2. **Use TestServer fixtures**: Always use `async_server` or `async_test_server` fixtures
80+
- `async_server`: Pre-configured server with unique socket
81+
- `async_test_server`: Factory for creating multiple servers
82+
83+
3. **Ensure isolation**: All tests must use unique sockets to avoid affecting:
84+
- Developer's active tmux sessions
85+
- Other concurrent tests
86+
- System tmux server
87+
88+
4. **Include cleanup**: All resources should be cleaned up
89+
- Sessions, windows, panes created during tests
90+
- Use fixture cleanup or explicit cleanup in tests
91+
92+
5. **Assert behavior, not values**: Test boolean conditions, types, lengths
93+
```python
94+
# Good - Tests behavior
95+
assert isinstance(result.stdout, list)
96+
assert len(result.stdout) > 0
97+
assert result.returncode == 0
98+
99+
# Bad - Tests exact values
100+
assert result.stdout == ['session1'] # Fragile!
101+
```
102+
103+
## Fixtures
104+
105+
Available from `conftest.py`:
106+
107+
- `async_server`: Async wrapper for server fixture
108+
- Provides Server instance with unique socket
109+
- Automatic cleanup via finalizer
110+
- Socket name: `libtmux_test{random}`
111+
112+
- `async_test_server`: Async wrapper for TestServer factory
113+
- Creates multiple unique servers
114+
- Each call returns new isolated server
115+
- All servers cleaned up automatically
116+
117+
## CPython-Inspired Patterns
118+
119+
Following CPython's asyncio test patterns:
120+
121+
1. **Use `asyncio.run()` in doctests**:
122+
```python
123+
>>> async def example():
124+
... result = await tmux_cmd_async('list-sessions')
125+
... return isinstance(result.stdout, list)
126+
>>> asyncio.run(example())
127+
True
128+
```
129+
130+
2. **Test concurrent operations with `asyncio.gather()`**:
131+
```python
132+
results = await asyncio.gather(
133+
tmux_cmd_async('cmd1'),
134+
tmux_cmd_async('cmd2'),
135+
tmux_cmd_async('cmd3'),
136+
)
137+
```
138+
139+
3. **Use `return_exceptions=True` for resilience**:
140+
```python
141+
results = await asyncio.gather(
142+
tmux_cmd_async('cmd1'),
143+
tmux_cmd_async('cmd2'),
144+
return_exceptions=True,
145+
)
146+
```
147+
148+
## Coverage Goals
149+
150+
Current coverage: ~25 async tests
151+
152+
Target coverage:
153+
- ✅ Core async functionality (tmux_cmd_async, get_version)
154+
- ✅ Pattern A (.acmd methods)
155+
- ✅ Pattern B (tmux_cmd_async)
156+
- ✅ Concurrent operations
157+
- ✅ Error handling
158+
- ⏳ AsyncEnvironmentMixin methods (pending)
159+
- ⏳ Version checking functions (pending)
160+
- ⏳ Edge cases and error conditions (pending)
161+
162+
## Best Practices
163+
164+
1. **Keep tests fast**: Use minimal tmux operations
165+
2. **Test behavior, not implementation**: Focus on observable outcomes
166+
3. **Use descriptive test names**: `test_pattern_a_creates_session_concurrently`
167+
4. **Document test purpose**: Add docstrings explaining what's being tested
168+
5. **Follow pytest conventions**: Use `test_*.py` naming, `Test*` classes
169+
170+
## See Also
171+
172+
- [pytest-asyncio documentation](https://pytest-asyncio.readthedocs.io/)
173+
- [CPython asyncio tests](https://github.com/python/cpython/tree/main/Lib/test/test_asyncio)
174+
- [libtmux async guide](../../docs/topics/async_programming.md)
175+
- [Async quickstart](../../docs/quickstart_async.md)

tests/asyncio/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
"""Async tests for libtmux.
2+
3+
This package contains all async-specific tests for libtmux's async support,
4+
organized following CPython's test structure patterns.
5+
"""
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)