buster/api/.cursor/rules/testing.mdc

135 lines
4.0 KiB
Plaintext

---
description: This is designed to help understand how to do testing in this project.
globs: src/*
---
# Testing Rules and Best Practices
## General Testing Guidelines
- All tests must be async and use tokio test framework
- Tests should be well-documented with clear test case descriptions and expected outputs
- Each test should focus on testing a single piece of functionality
- Tests should be independent and not rely on the state of other tests
- Use meaningful test names that describe what is being tested
## Unit Tests
- Unit tests should be inline with the code they are testing using `#[cfg(test)]` modules
- Each public function should have corresponding unit tests
- Mock external dependencies using mockito for HTTP calls
- Use `mockito::Server::new_async()` instead of `mockito::Server::new()`
- Test both success and error cases
- Test edge cases and boundary conditions
## Integration Tests
- Integration tests should be placed in the `/tests` directory
- Organize integration tests to mirror the main codebase structure
- Each major feature/resource should have its own test file
- Test the interaction between multiple components
- Use real dependencies when possible, mock only what's necessary
- Include end-to-end workflow tests
## Test Structure
```rust
#[cfg(test)]
mod tests {
use super::*;
use mockito;
use tokio;
// Optional: Setup function for common test initialization
async fn setup() -> TestContext {
// Setup code here
}
#[tokio::test]
async fn test_name() {
// Test case description in comments
// Expected output in comments
// Arrange
// Setup test data and dependencies
// Act
// Execute the function being tested
// Assert
// Verify the results
}
}
```
## Mocking Guidelines
- Use mockito for HTTP service mocks
- Create mock responses that match real API responses
- Include both successful and error responses in mocks
- Clean up mocks after tests complete
## Error Testing
- Test error conditions and error handling
- Verify error messages and error types
- Test timeout scenarios
- Test connection failures
- Test invalid input handling
## Database Testing
- Use a separate test database for integration tests
- Clean up test data after tests complete
- Test database transactions and rollbacks
- Test database connection error handling
## WebSocket Testing
- Test WebSocket connection establishment
- Test message sending and receiving
- Test connection closure handling
- Test reconnection logic
- Test concurrent WebSocket connections
## Performance Testing
- Include basic performance tests for critical paths
- Test response times under normal conditions
- Test handling of concurrent requests
- Test resource cleanup
## Test Output
- Tests should provide clear error messages
- Use descriptive assert messages
- Print relevant debug information in test failures
- Log test execution progress for long-running tests
## CI/CD Considerations
- All tests must pass in CI environment
- Tests should be reproducible
- Tests should not have external dependencies that could fail CI
- Test execution time should be reasonable
## Example Test
```rust
#[cfg(test)]
mod tests {
use super::*;
use mockito;
use tokio;
#[tokio::test]
async fn test_api_call_success() {
// Test case: Successful API call returns expected response
// Expected: Response contains user data with status 200
let mut server = mockito::Server::new_async().await;
let mock = server
.mock("GET", "/api/user")
.match_header("authorization", "Bearer test-token")
.with_status(200)
.with_body(r#"{"id": "123", "name": "Test User"}"#)
.create();
let client = ApiClient::new(server.url());
let response = client.get_user().await.unwrap();
assert_eq!(response.id, "123");
assert_eq!(response.name, "Test User");
mock.assert();
}
}
```