0
# Test Execution
1
2
Green's test execution system provides multi-process parallel test running with process pool management, worker initialization, and comprehensive test orchestration for improved performance.
3
4
## Capabilities
5
6
### Main Test Runner
7
8
The core function that orchestrates test execution with Green's enhanced features including parallel processing, coverage integration, and result aggregation.
9
10
```python { .api }
11
def run(suite, stream, args, testing=False):
12
"""
13
Run tests with Green's enhanced features.
14
15
Args:
16
suite: Test suite to run (GreenTestSuite or unittest.TestSuite)
17
stream: Output stream, will be wrapped in GreenStream if not already
18
args: Configuration namespace containing execution parameters:
19
- processes: Number of parallel processes (0 = auto-detect)
20
- run_coverage: Enable coverage reporting
21
- initializer: Worker process initializer function
22
- finalizer: Worker process finalizer function
23
- debug: Debug level for execution details
24
testing (bool): Enable testing mode behavior (affects coverage and output)
25
26
Returns:
27
GreenTestResult: Comprehensive test execution results with:
28
- Individual test outcomes
29
- Timing information
30
- Coverage data (if enabled)
31
- Process execution statistics
32
33
Example:
34
from green.runner import run
35
from green.loader import GreenTestLoader
36
from green.output import GreenStream
37
from green.config import get_default_args
38
import sys
39
40
# Load tests
41
loader = GreenTestLoader()
42
suite = loader.loadTargets(['tests/'])
43
44
# Configure execution
45
args = get_default_args()
46
args.processes = 4
47
args.run_coverage = True
48
49
# Run tests
50
stream = GreenStream(sys.stdout)
51
result = run(suite, stream, args)
52
53
print(f"Tests run: {result.testsRun}")
54
print(f"Success: {result.wasSuccessful()}")
55
"""
56
```
57
58
### Worker Process Management
59
60
Helper class for managing worker process initialization and cleanup functions.
61
62
```python { .api }
63
class InitializerOrFinalizer:
64
"""
65
Manages worker process setup and teardown functions.
66
67
Allows specifying custom initialization and cleanup code that runs
68
in each worker process before and after test execution.
69
"""
70
71
def __init__(self, dotted_function):
72
"""
73
Initialize with a dotted function name.
74
75
Args:
76
dotted_function (str): Fully qualified function name like
77
'mymodule.setup_function' or
78
'mypackage.tests.init_worker'
79
80
Example:
81
initializer = InitializerOrFinalizer('tests.setup.init_database')
82
finalizer = InitializerOrFinalizer('tests.setup.cleanup_database')
83
"""
84
85
def __call__(self, *args):
86
"""
87
Execute the configured function.
88
89
Args:
90
*args: Arguments to pass to the function
91
92
Raises:
93
InitializerOrFinalizerError: If function cannot be loaded or executed
94
"""
95
```
96
97
## Usage Examples
98
99
### Basic Test Execution
100
101
```python
102
from green.runner import run
103
from green.loader import GreenTestLoader
104
from green.output import GreenStream
105
from green.config import parseArguments, mergeConfig
106
import sys
107
108
# Load and configure
109
args = parseArguments(['tests/'])
110
config = mergeConfig(args)
111
112
loader = GreenTestLoader()
113
suite = loader.loadTargets(config.targets)
114
115
# Execute tests
116
stream = GreenStream(sys.stdout)
117
result = run(suite, stream, config)
118
119
# Check results
120
if result.wasSuccessful():
121
print("All tests passed!")
122
exit(0)
123
else:
124
print(f"Tests failed: {len(result.failures)} failures, {len(result.errors)} errors")
125
exit(1)
126
```
127
128
### Parallel Execution Configuration
129
130
```python
131
from green.runner import run
132
from green.config import get_default_args
133
134
# Configure parallel execution
135
args = get_default_args()
136
args.processes = 8 # Use 8 processes
137
args.debug = 1 # Enable debug output
138
139
# Auto-detect optimal process count
140
args.processes = 0 # Green will use multiprocessing.cpu_count()
141
142
# Single-process execution (useful for debugging)
143
args.processes = 1
144
```
145
146
### Custom Worker Initialization
147
148
```python
149
from green.runner import run, InitializerOrFinalizer
150
from green.config import get_default_args
151
152
# Create worker setup functions
153
def setup_test_database():
154
"""Initialize test database connection in worker process."""
155
import sqlite3
156
global db_connection
157
db_connection = sqlite3.connect(':memory:')
158
# Setup test tables, etc.
159
160
def cleanup_test_database():
161
"""Clean up test database in worker process."""
162
global db_connection
163
if db_connection:
164
db_connection.close()
165
166
# Configure with initializer/finalizer
167
args = get_default_args()
168
args.initializer = 'tests.setup.setup_test_database'
169
args.finalizer = 'tests.setup.cleanup_test_database'
170
171
# The InitializerOrFinalizer will be used internally
172
result = run(suite, stream, args)
173
```
174
175
### Coverage Integration
176
177
```python
178
from green.runner import run
179
from green.config import get_default_args
180
181
# Enable coverage
182
args = get_default_args()
183
args.run_coverage = True
184
args.coverage_config_file = '.coveragerc' # Custom coverage config
185
args.omit_patterns = ['*/tests/*', '*/venv/*'] # Patterns to omit
186
187
result = run(suite, stream, args)
188
189
# Coverage data will be automatically collected and reported
190
```
191
192
### Debug Mode Execution
193
194
```python
195
from green.runner import run
196
from green.config import get_default_args
197
198
# Enable detailed debug output
199
args = get_default_args()
200
args.debug = 2 # Higher debug levels provide more detail
201
args.processes = 1 # Single process for easier debugging
202
203
result = run(suite, stream, args)
204
```
205
206
### Error Handling and Recovery
207
208
```python
209
from green.runner import run
210
from green.exceptions import InitializerOrFinalizerError
211
212
try:
213
result = run(suite, stream, args)
214
215
# Check for various error conditions
216
if result.errors:
217
print(f"Test errors occurred: {len(result.errors)}")
218
for test, error in result.errors:
219
print(f" {test}: {error}")
220
221
if result.failures:
222
print(f"Test failures occurred: {len(result.failures)}")
223
for test, failure in result.failures:
224
print(f" {test}: {failure}")
225
226
except InitializerOrFinalizerError as e:
227
print(f"Worker process setup failed: {e}")
228
# Handle worker initialization errors
229
230
except KeyboardInterrupt:
231
print("Test execution interrupted by user")
232
# Handle Ctrl+C gracefully
233
234
except Exception as e:
235
print(f"Unexpected error during test execution: {e}")
236
# Handle other execution errors
237
```
238
239
### Advanced Execution Scenarios
240
241
```python
242
from green.runner import run
243
from green.suite import GreenTestSuite
244
from green.config import get_default_args
245
246
# Custom test suite configuration
247
suite = GreenTestSuite()
248
# Add tests to suite...
249
250
# Configure for specific execution environment
251
args = get_default_args()
252
253
# CI/CD environment
254
if os.environ.get('CI'):
255
args.processes = 0 # Auto-detect
256
args.run_coverage = True
257
args.junit_report = 'test-results.xml'
258
args.verbose = 1 # Minimal output for CI logs
259
260
# Development environment
261
else:
262
args.processes = 2 # Don't overwhelm development machine
263
args.verbose = 2 # More verbose for development
264
args.debug = 1 # Enable debug output
265
266
result = run(suite, stream, args)
267
```
268
269
### Integration with Custom Test Frameworks
270
271
```python
272
from green.runner import run
273
from green.loader import GreenTestLoader
274
import unittest
275
276
class CustomTestResult(unittest.TestResult):
277
"""Custom result processor."""
278
pass
279
280
# Green can work with custom test frameworks
281
loader = GreenTestLoader()
282
suite = loader.loadTargets(['tests/'])
283
284
# Green will handle the parallel execution and result aggregation
285
result = run(suite, stream, args)
286
287
# Post-process results with custom logic
288
custom_processor = CustomTestResult()
289
# Process results as needed...
290
```
291
292
## Process Pool Management
293
294
Green uses a custom process pool implementation for enhanced parallel execution:
295
296
### Features
297
- **Daemonless Processes**: Workers can spawn their own subprocesses
298
- **Custom Finalizers**: Clean shutdown of worker processes
299
- **Enhanced Logging**: Better error reporting from worker processes
300
- **Coverage Integration**: Automatic coverage data collection from workers
301
- **Signal Handling**: Graceful handling of interruption signals
302
303
### Configuration Options
304
305
```python
306
# Process count options
307
args.processes = 0 # Auto-detect (multiprocessing.cpu_count())
308
args.processes = 1 # Single process (no parallelization)
309
args.processes = 4 # Specific process count
310
args.processes = -1 # Use all available CPUs
311
312
# Worker customization
313
args.initializer = 'module.setup_function' # Run in each worker on startup
314
args.finalizer = 'module.cleanup_function' # Run in each worker on shutdown
315
```
316
317
## Performance Considerations
318
319
### Optimal Process Count
320
- **CPU-bound tests**: processes = cpu_count()
321
- **I/O-bound tests**: processes = cpu_count() * 2
322
- **Memory-intensive tests**: processes = cpu_count() / 2
323
- **Development/debugging**: processes = 1
324
325
### Test Organization for Parallelization
326
- Group related tests in the same module
327
- Avoid shared state between test methods
328
- Use fixtures for test data setup/teardown
329
- Consider process-local resources (databases, files)
330
331
### Coverage Overhead
332
- Coverage adds ~20-30% execution time
333
- Benefits from parallel execution
334
- Use `.coveragerc` to optimize data collection
335
- Consider coverage sampling for very large test suites