Skip to content

Commit 4738317

Browse files
committed
Add comprehensive test suite and restructure tests for ACCESS-MOPPeR
1 parent b17091f commit 4738317

4 files changed

Lines changed: 563 additions & 185 deletions

File tree

tests/README.md

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
# ACCESS-MOPPeR Test Suite
2+
3+
This directory contains the comprehensive test suite for ACCESS-MOPPeR.
4+
5+
## Test Structure
6+
7+
### 📁 Test Organization
8+
9+
```
10+
tests/
11+
├── conftest.py # Shared fixtures and utilities
12+
├── pytest.ini # Test configuration
13+
├── test_smoke.py # Basic smoke tests
14+
├── test_mop.py # Legacy (deprecated)
15+
├── unit/ # Unit tests
16+
│ ├── test_base.py # BaseCMORiser tests
17+
│ ├── test_batch_cmoriser.py # Batch processing tests
18+
│ ├── test_templates.py # Template tests
19+
│ └── test_tracking.py # Tracking functionality tests
20+
├── integration/ # Integration tests
21+
│ ├── test_cmoriser_integration.py # CMORiser integration
22+
│ ├── test_batch_integration.py # Batch processing integration
23+
│ └── test_full_cmorisation.py # Full CMOR workflow tests
24+
├── e2e/ # End-to-end tests
25+
│ └── test_end_to_end.py # Real data processing tests
26+
├── performance/ # Performance and memory tests
27+
│ └── test_memory_usage.py # Memory usage and optimization tests
28+
├── mocks/ # Mock data and utilities
29+
│ ├── mock_data.py # Mock dataset generators
30+
│ ├── mock_files.py # Mock file utilities
31+
│ └── mock_pbs.py # Mock PBS/job scheduler
32+
├── data/ # Test data files
33+
└── scripts/ # Test utilities and scripts
34+
```
35+
36+
## 🏃 Running Tests
37+
38+
### Run all tests
39+
```bash
40+
pytest tests/
41+
```
42+
43+
### Run by category
44+
```bash
45+
# Unit tests (fast)
46+
pytest tests/unit/ -m unit
47+
48+
# Integration tests (medium speed)
49+
pytest tests/integration/ -m integration
50+
51+
# End-to-end tests (slow, requires test data)
52+
pytest tests/e2e/ -m e2e
53+
54+
# Performance tests (very slow)
55+
pytest tests/performance/ -m performance
56+
```
57+
58+
### Run by speed
59+
```bash
60+
# Fast tests only (good for development)
61+
pytest tests/ -m "not slow"
62+
63+
# Include slow tests (good for CI)
64+
pytest tests/ -m "slow or not slow"
65+
```
66+
67+
### Run smoke tests
68+
```bash
69+
# Quick verification that basic functionality works
70+
pytest tests/test_smoke.py
71+
```
72+
73+
## 🏷️ Test Markers
74+
75+
Tests are marked with the following categories:
76+
77+
- `unit`: Unit tests (fast, isolated)
78+
- `integration`: Integration tests (medium speed, may use mocks)
79+
- `e2e`: End-to-end tests (slow, requires real data)
80+
- `slow`: Tests that take significant time
81+
- `performance`: Performance and memory benchmarks
82+
- `memory`: Memory usage tests
83+
84+
## 📊 Test Coverage
85+
86+
Run tests with coverage reporting:
87+
```bash
88+
pytest tests/ --cov=access_mopper --cov-report=html --cov-report=term
89+
```
90+
91+
View coverage report:
92+
```bash
93+
open htmlcov/index.html
94+
```
95+
96+
## 🔧 Test Configuration
97+
98+
Key configuration in `pytest.ini`:
99+
- Test discovery patterns
100+
- Marker definitions
101+
- Warning filters
102+
- Minimum pytest version requirements
103+
104+
Shared fixtures in `conftest.py`:
105+
- `temp_dir`: Temporary directory for test outputs
106+
- `parent_experiment_config`: Standard parent experiment metadata
107+
- `mock_netcdf_dataset`: Mock xarray dataset
108+
- `mock_config`: Standard CMIP6 configuration
109+
- `batch_config`: Batch processing configuration
110+
111+
## 📝 Test Data
112+
113+
Test data is organized in `tests/data/`:
114+
- `esm1-6/`: Small ACCESS-ESM1.5 sample files
115+
- `om3/`: Ocean model test data
116+
- `small/`: Minimal test datasets
117+
- `fixtures/`: Fixed test configurations
118+
119+
### Adding Test Data
120+
121+
When adding new test data:
122+
1. Keep files small (< 10MB if possible)
123+
2. Use representative but minimal datasets
124+
3. Document the source and contents
125+
4. Use `pytest.mark.skipif` for optional data files
126+
127+
## 🏗️ Writing Tests
128+
129+
### Test Naming Convention
130+
- Test files: `test_*.py`
131+
- Test functions: `test_*`
132+
- Test classes: `Test*`
133+
134+
### Best Practices
135+
136+
1. **Use appropriate test categories**: Mark tests with `@pytest.mark.unit`, `@pytest.mark.integration`, etc.
137+
138+
2. **Use fixtures for setup**: Leverage fixtures in `conftest.py` for common setup.
139+
140+
3. **Make tests independent**: Each test should be able to run in isolation.
141+
142+
4. **Use descriptive names**: Test names should clearly indicate what is being tested.
143+
144+
5. **Test error conditions**: Include tests for error handling and edge cases.
145+
146+
6. **Use subtests for parameterized tests**: When testing multiple similar cases.
147+
148+
### Example Test Structure
149+
150+
```python
151+
import pytest
152+
from access_mopper import ACCESS_ESM_CMORiser
153+
154+
class TestNewFeature:
155+
"""Tests for new feature functionality."""
156+
157+
@pytest.mark.unit
158+
def test_basic_functionality(self, mock_config):
159+
"""Test basic feature works correctly."""
160+
# Test implementation
161+
162+
@pytest.mark.integration
163+
@pytest.mark.skipif(not_data_available, reason="Test data not available")
164+
def test_with_real_data(self, parent_experiment_config):
165+
"""Test feature with real data files."""
166+
# Test implementation
167+
168+
@pytest.mark.slow
169+
def test_performance_characteristics(self):
170+
"""Test that feature meets performance requirements."""
171+
# Performance test implementation
172+
```
173+
174+
## 🐛 Debugging Tests
175+
176+
### Running specific tests
177+
```bash
178+
# Run single test
179+
pytest tests/unit/test_base.py::TestBaseCMORiser::test_init_with_valid_params
180+
181+
# Run with verbose output
182+
pytest tests/ -v
183+
184+
# Stop on first failure
185+
pytest tests/ -x
186+
187+
# Drop into debugger on failure
188+
pytest tests/ --pdb
189+
```
190+
191+
### Test output
192+
- Use `pytest.skip()` for tests that should be skipped
193+
- Use `pytest.xfail()` for known failures
194+
- Use `pytest.fail()` with descriptive messages
195+
196+
## 🔄 Migration from Legacy Tests
197+
198+
The original `test_mop.py` has been restructured:
199+
200+
**Old structure**:
201+
- All tests in single file
202+
- Duplicate parametrized tests
203+
- Mixed concerns (smoke + integration + validation)
204+
205+
**New structure**:
206+
- `test_smoke.py`: Basic import and initialization tests
207+
- `tests/integration/test_full_cmorisation.py`: Comprehensive CMOR tests
208+
- Proper separation of unit, integration, and e2e tests
209+
210+
### Backward Compatibility
211+
212+
The old `test_mop.py` file is maintained with a deprecation notice to ensure existing workflows continue to work.
213+
214+
## 🚀 CI/CD Integration
215+
216+
Suggested CI pipeline:
217+
218+
1. **Pull Request**: Run unit tests + smoke tests
219+
2. **Merge to main**: Run unit + integration tests
220+
3. **Release**: Run full test suite including e2e and performance tests
221+
222+
Example GitHub Actions workflow:
223+
```yaml
224+
- name: Run fast tests
225+
run: pytest tests/ -m "not slow"
226+
227+
- name: Run slow tests
228+
run: pytest tests/ -m "slow"
229+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
230+
```

0 commit comments

Comments
 (0)