|
| 1 | +# HURL Developer Testing Guide |
| 2 | + |
| 3 | +This guide covers the advanced test scheme and data sources implemented in HURL for performance and integration testing. |
| 4 | + |
| 5 | +## Test Data Sources |
| 6 | + |
| 7 | +HURL supports three distinct test data sources with automatic fallback: |
| 8 | + |
| 9 | +### 1. 🎭 Mocked Data (Always Available) |
| 10 | +- **Location**: `tests/mocked_data/` |
| 11 | +- **Purpose**: Anonymized XML fixtures checked into repository |
| 12 | +- **Use Case**: CI/CD, unit tests, onboarding |
| 13 | +- **Availability**: ✅ Always available (checked into repo) |
| 14 | +- **Security**: ✅ Safe (no sensitive data) |
| 15 | + |
| 16 | +### 2. 💾 Cached Data (Local Development) |
| 17 | +- **Location**: `tests/fixture_cache/` |
| 18 | +- **Purpose**: Local cache of real remote API responses |
| 19 | +- **Use Case**: Fast offline development with realistic data |
| 20 | +- **Availability**: ⚠️ Must be generated locally (not in CI) |
| 21 | +- **Security**: ⚠️ May contain sensitive data (never committed) |
| 22 | + |
| 23 | +### 3. 🌐 Remote Data (Live API) |
| 24 | +- **Location**: Direct API calls to live servers |
| 25 | +- **Purpose**: Cache refresh, high-fidelity integration testing |
| 26 | +- **Use Case**: Fixture updates, integration validation |
| 27 | +- **Availability**: ⚠️ Requires network + credentials |
| 28 | +- **Security**: ⚠️ Sensitive (never for CI) |
| 29 | + |
| 30 | +## Test Classification |
| 31 | + |
| 32 | +### 🧪 Unit Tests |
| 33 | +```bash |
| 34 | +pytest -m unit |
| 35 | +``` |
| 36 | +- Use only mocked data |
| 37 | +- Fast and reliable |
| 38 | +- Run in CI |
| 39 | +- No network dependencies |
| 40 | + |
| 41 | +### 🔧 Integration Tests |
| 42 | +```bash |
| 43 | +pytest -m integration |
| 44 | +``` |
| 45 | +- Can use any data source |
| 46 | +- Test end-to-end functionality |
| 47 | +- May require environment setup |
| 48 | + |
| 49 | +### ⚡ Performance Tests |
| 50 | +```bash |
| 51 | +pytest -m performance |
| 52 | +``` |
| 53 | +- Prefer real data when available |
| 54 | +- Measure parsing vs network latency |
| 55 | +- Detect regressions |
| 56 | + |
| 57 | +## CLI Usage |
| 58 | + |
| 59 | +### Data Source Selection |
| 60 | +```bash |
| 61 | +# Auto-select (cached → mocked fallback) |
| 62 | +pytest --data-source=auto |
| 63 | + |
| 64 | +# Force mocked data only (CI-safe) |
| 65 | +pytest --data-source=mocked |
| 66 | + |
| 67 | +# Prefer cached data |
| 68 | +pytest --data-source=cached |
| 69 | + |
| 70 | +# Force remote API calls (requires credentials) |
| 71 | +pytest --data-source=remote |
| 72 | +``` |
| 73 | + |
| 74 | +### Test Categories |
| 75 | +```bash |
| 76 | +# Run only unit tests (fast, CI-safe) |
| 77 | +pytest -m unit |
| 78 | + |
| 79 | +# Run integration tests with mocked data |
| 80 | +pytest -m integration --data-source=mocked |
| 81 | + |
| 82 | +# Run performance tests with real data |
| 83 | +pytest -m performance --data-source=cached |
| 84 | + |
| 85 | +# Skip remote-dependent tests |
| 86 | +pytest -m "not remote" |
| 87 | +``` |
| 88 | + |
| 89 | +### Fixture Management |
| 90 | +```bash |
| 91 | +# Update cached fixtures from remote API |
| 92 | +pytest --update -m "remote and update" |
| 93 | + |
| 94 | +# Skip tests when data unavailable |
| 95 | +pytest --skip-missing-data |
| 96 | + |
| 97 | +# Verbose data source reporting |
| 98 | +pytest -v --data-source=auto |
| 99 | +``` |
| 100 | + |
| 101 | +## Environment Setup |
| 102 | + |
| 103 | +### Required Environment Variables |
| 104 | +```bash |
| 105 | +export HILLTOP_BASE_URL="https://your-hilltop-server.com" |
| 106 | +export HILLTOP_HTS_ENDPOINT="your-endpoint.hts" |
| 107 | +``` |
| 108 | + |
| 109 | +Or create `.env` file: |
| 110 | +```env |
| 111 | +HILLTOP_BASE_URL=https://your-hilltop-server.com |
| 112 | +HILLTOP_HTS_ENDPOINT=your-endpoint.hts |
| 113 | +``` |
| 114 | + |
| 115 | +### CI/CD Environment |
| 116 | +```bash |
| 117 | +# CI-safe test run (no credentials required) |
| 118 | +pytest -m "unit" --data-source=mocked |
| 119 | + |
| 120 | +# Integration tests with mocked data |
| 121 | +pytest -m "integration" --data-source=mocked |
| 122 | +``` |
| 123 | + |
| 124 | +### Local Development |
| 125 | +```bash |
| 126 | +# Full test suite with fallback |
| 127 | +pytest |
| 128 | + |
| 129 | +# Generate cached fixtures for faster iteration |
| 130 | +pytest --update -m "remote and update" |
| 131 | + |
| 132 | +# Work offline with cached data |
| 133 | +pytest --data-source=cached |
| 134 | +``` |
| 135 | + |
| 136 | +## Security Guidelines |
| 137 | + |
| 138 | +### ⚠️ NEVER commit cached data |
| 139 | +```bash |
| 140 | +# Cached data is in .gitignore |
| 141 | +echo "tests/fixture_cache/*.xml" >> .gitignore |
| 142 | +``` |
| 143 | + |
| 144 | +### ✅ Safe for CI |
| 145 | +- Mocked data is anonymized |
| 146 | +- No credentials in mocked fixtures |
| 147 | +- No sensitive server information |
| 148 | + |
| 149 | +### 🔒 Secure Development |
| 150 | +1. Use separate test servers when possible |
| 151 | +2. Rotate credentials regularly |
| 152 | +3. Limit remote test frequency |
| 153 | +4. Review cached data before sharing |
| 154 | + |
| 155 | +## Developer Workflows |
| 156 | + |
| 157 | +### 🚀 Quick Start (New Developer) |
| 158 | +```bash |
| 159 | +# 1. Clone repo |
| 160 | +git clone https://github.com/HorizonsRC/hurl.git |
| 161 | +cd hurl |
| 162 | + |
| 163 | +# 2. Install dependencies |
| 164 | +pip install -e . |
| 165 | + |
| 166 | +# 3. Run unit tests (no setup required) |
| 167 | +pytest -m unit |
| 168 | + |
| 169 | +# 4. Run integration tests with mocked data |
| 170 | +pytest -m integration --data-source=mocked |
| 171 | +``` |
| 172 | + |
| 173 | +### 🔄 Regular Development |
| 174 | +```bash |
| 175 | +# Daily development (fast, reliable) |
| 176 | +pytest -m "not remote" --data-source=cached |
| 177 | + |
| 178 | +# When changing schemas or adding features |
| 179 | +pytest --update -m "remote and update" # Refresh fixtures |
| 180 | +pytest -m integration # Validate changes |
| 181 | +``` |
| 182 | + |
| 183 | +### 🚢 Pre-deployment |
| 184 | +```bash |
| 185 | +# Full CI simulation |
| 186 | +pytest -m "unit" --data-source=mocked |
| 187 | + |
| 188 | +# Integration validation |
| 189 | +pytest -m "integration" --data-source=cached |
| 190 | + |
| 191 | +# Performance regression check |
| 192 | +pytest -m "performance" --data-source=cached |
| 193 | +``` |
| 194 | + |
| 195 | +## Test Data Management |
| 196 | + |
| 197 | +### Generating Mocked Data |
| 198 | +```python |
| 199 | +# Create anonymized fixtures from real data |
| 200 | +def anonymize_xml(real_xml): |
| 201 | + # Replace sensitive values |
| 202 | + return real_xml.replace("Real Site", "Test Site Alpha") |
| 203 | +``` |
| 204 | + |
| 205 | +### Updating Cached Data |
| 206 | +```bash |
| 207 | +# Update all cached fixtures |
| 208 | +pytest --update -m "remote and update" |
| 209 | + |
| 210 | +# Update specific fixture category |
| 211 | +pytest --update tests/test_schemas/test_responses/test_status_response.py |
| 212 | +``` |
| 213 | + |
| 214 | +### Missing Data Handling |
| 215 | +```bash |
| 216 | +# Skip gracefully when data unavailable |
| 217 | +pytest --skip-missing-data |
| 218 | + |
| 219 | +# See what data sources are available |
| 220 | +pytest -v # Shows data source used for each test |
| 221 | +``` |
| 222 | + |
| 223 | +## Test Matrix |
| 224 | + |
| 225 | +| Test Type | Mocked | Cached | Remote | CI Safe | Use Case | |
| 226 | +|-----------|---------|---------|---------|---------|----------| |
| 227 | +| Unit | ✅ | ✅ | ❌ | ✅ | Schema validation, logic | |
| 228 | +| Integration | ✅ | ✅ | ✅ | ⚠️* | End-to-end workflows | |
| 229 | +| Performance | ⚠️** | ✅ | ✅ | ⚠️** | Latency, regressions | |
| 230 | +| Remote Validation | ❌ | ❌ | ✅ | ❌ | Cache refresh | |
| 231 | + |
| 232 | +*\* Integration tests are CI-safe when using mocked data* |
| 233 | +*\*\* Performance tests work with mocked data but prefer real data* |
| 234 | + |
| 235 | +## Troubleshooting |
| 236 | + |
| 237 | +### Common Issues |
| 238 | + |
| 239 | +#### "No data available for {type}/{file}" |
| 240 | +```bash |
| 241 | +# Solution: Generate missing data or use different source |
| 242 | +pytest --data-source=mocked # Use available mocked data |
| 243 | +pytest --update -m remote # Generate cached data |
| 244 | +``` |
| 245 | + |
| 246 | +#### "Remote tests require environment variables" |
| 247 | +```bash |
| 248 | +# Solution: Set required variables |
| 249 | +export HILLTOP_BASE_URL="https://your-server.com" |
| 250 | +export HILLTOP_HTS_ENDPOINT="endpoint.hts" |
| 251 | +``` |
| 252 | + |
| 253 | +#### "Connection failed" during --update |
| 254 | +```bash |
| 255 | +# Solution: Check network and credentials |
| 256 | +curl $HILLTOP_BASE_URL/$HILLTOP_HTS_ENDPOINT # Test connectivity |
| 257 | +pytest -m "not remote" # Skip remote tests |
| 258 | +``` |
| 259 | + |
| 260 | +### Debug Information |
| 261 | +```bash |
| 262 | +# Verbose output shows data source decisions |
| 263 | +pytest -v |
| 264 | + |
| 265 | +# See which tests are being skipped and why |
| 266 | +pytest -v --skip-missing-data |
| 267 | + |
| 268 | +# Show available test markers |
| 269 | +pytest --markers |
| 270 | +``` |
| 271 | + |
| 272 | +## Contributing New Tests |
| 273 | + |
| 274 | +### Adding Unit Tests |
| 275 | +```python |
| 276 | +@pytest.mark.unit |
| 277 | +@pytest.mark.mocked_data |
| 278 | +def test_new_feature(fixture_name): |
| 279 | + """Unit test using mocked data.""" |
| 280 | + # Test logic here |
| 281 | +``` |
| 282 | + |
| 283 | +### Adding Integration Tests |
| 284 | +```python |
| 285 | +@pytest.mark.integration |
| 286 | +def test_integration_workflow(fixture_name): |
| 287 | + """Integration test supporting multiple data sources.""" |
| 288 | + # Test workflow here |
| 289 | +``` |
| 290 | + |
| 291 | +### Creating New Fixtures |
| 292 | +```python |
| 293 | +# In test file: |
| 294 | +@pytest.fixture |
| 295 | +def new_fixture(request, httpx_mock, remote_client): |
| 296 | + """New fixture with data source support.""" |
| 297 | + manager = TestDataManager(Path(__file__)) |
| 298 | + data_file = manager.get_data_file("new_type", "response.xml") |
| 299 | + |
| 300 | + if data_file is None: |
| 301 | + pytest.skip("No test data available") |
| 302 | + |
| 303 | + return data_file.read_text(encoding="utf-8") |
| 304 | +``` |
| 305 | + |
| 306 | +## Best Practices |
| 307 | + |
| 308 | +### ✅ Do |
| 309 | +- Use unit tests for schema validation |
| 310 | +- Prefer mocked data for CI |
| 311 | +- Update cached fixtures regularly |
| 312 | +- Test with multiple data sources |
| 313 | +- Add clear test markers |
| 314 | + |
| 315 | +### ❌ Don't |
| 316 | +- Commit cached data to repo |
| 317 | +- Hard-code server responses in tests |
| 318 | +- Skip environment variable validation |
| 319 | +- Assume network connectivity |
| 320 | +- Mix test data sources without markers |
| 321 | + |
| 322 | +--- |
| 323 | + |
| 324 | +This testing scheme ensures reliable CI/CD while supporting rich local development workflows with real API data. |
0 commit comments