# Unit Test Guidelines
This document outlines the unit testing strategy for mq-bridge.
## Test Organization
### Current Test Structure
```
tests/
├── integration/ # Integration tests (require Docker)
│ ├── kafka.rs
│ ├── nats.rs
│ ├── amqp.rs
│ ├── mqtt.rs
│ ├── mongodb.rs
│ ├── aws.rs
│ ├── memory.rs
│ └── route.rs
├── integration_test.rs # Main integration test runner
├── request_reply_test.rs # Request-reply pattern tests
├── memory_test.rs # Memory-only performance tests
└── performance_pipeline.rs # Pipeline performance tests
```
### Unit Tests in Source Files
Each module should have unit tests in a `#[cfg(test)]` block:
- `src/models.rs` - Configuration parsing tests
- `src/canonical_message.rs` - Message creation/parsing tests
- `src/route.rs` - Route execution logic tests
- `src/endpoints/*.rs` - Endpoint-specific tests
- `src/middleware/*.rs` - Middleware behavior tests
## Test Categories
### 1. Unit Tests (Fast, No I/O)
Test individual functions and types in isolation:
```rust
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_canonical_message_creation() {
let msg = CanonicalMessage::new(b"test".to_vec(), None);
assert_eq!(msg.payload, b"test");
}
}
```
### 2. Integration Tests (Require Services)
Test with real message brokers/services via Docker:
```rust
#[tokio::test]
#[ignore] // Requires Docker
async fn test_kafka_consumer() {
// Setup Kafka, test consumer
}
```
### 3. Memory Tests (Fast, No External Dependencies)
Test using in-memory channels:
```rust
#[tokio::test]
async fn test_memory_route() {
let input = Endpoint::new_memory("test_in", 100);
let output = Endpoint::new_memory("test_out", 100);
// Test route execution
}
```
## Test Coverage Goals
### High Priority (Critical Path)
- [x] Message creation and parsing
- [x] Route execution (sequential and concurrent)
- [x] Memory endpoints
- [ ] Error handling and propagation
- [ ] Middleware chaining
- [ ] Configuration parsing (YAML, JSON, env vars)
### Medium Priority (Important Features)
- [ ] All endpoint types (Kafka, NATS, AMQP, MQTT, MongoDB, SQLx, gRPC, ZeroMQ, File, AWS, IBM MQ, HTTP)
- [ ] Middleware implementations (retry, DLQ, deduplication)
- [ ] Type handlers
- [ ] Fanout and switch endpoints
- [ ] TLS configuration
### Lower Priority (Edge Cases)
- [ ] Large message handling
- [ ] Concurrent route execution edge cases
- [ ] Resource cleanup
- [ ] Configuration validation
## Writing New Tests
### Test Naming Convention
- Unit tests: `test_<functionality>`
- Integration tests: `test_<endpoint>_<scenario>`
- Performance tests: `bench_<operation>`
### Example Test Template
```rust
#[cfg(test)]
mod tests {
use super::*;
use crate::CanonicalMessage;
#[tokio::test]
async fn test_example() {
// Arrange
let input = Endpoint::new_memory("test", 10);
// Act
let result = some_function(input).await;
// Assert
assert!(result.is_ok());
}
}
```
### Integration Test Template
```rust
#[tokio::test]
#[ignore] // Requires Docker
async fn test_kafka_integration() {
use crate::tests::integration::common::*;
// Start Docker services
run_test_with_docker("tests/integration/docker-compose/kafka.yml", || async {
// Test implementation
}).await;
}
```
## Running Tests
```bash
# All tests
cargo test
# Unit tests only (fast)
cargo test --lib
# Integration tests (requires Docker)
cargo test --test integration_test --features full --release -- --ignored --nocapture --test-threads=1
# Request-reply tests (requires Docker)
cargo test --test request_reply_test --features full --release -- --ignored --nocapture --test-threads=1
# Memory tests
cargo test --test memory_test --features integration-test --release -- --nocapture
# Specific test
cargo test test_name
# With output
cargo test -- --nocapture
```
## Test Data
Use fixtures for common test data:
```rust
fn create_test_message() -> CanonicalMessage {
CanonicalMessage::new(b"test payload".to_vec(), None)
}
fn create_test_route() -> Route {
Route::new(
Endpoint::new_memory("input", 100),
Endpoint::new_memory("output", 100),
)
}
```
## Mocking
For testing without external dependencies:
- Use `MemoryEndpoint` for in-memory message passing
- Use `NullPublisher` for testing consumers without side effects
- Use `StaticEndpoint` for predictable responses
## Performance Testing
Performance tests should:
- Use `criterion` for benchmarking
- Run in `benches/` directory
- Be marked with `#[ignore]` in CI
- Compare against baseline metrics
## Continuous Integration
- Unit tests run on every PR
- Integration tests run on main branch (may be flaky)
- Performance benchmarks run on schedule
- All tests must pass before merging