mirror of https://github.com/buster-so/buster.git
135 lines
4.0 KiB
Plaintext
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();
|
|
}
|
|
}
|
|
``` |