automatic integratino test set up

This commit is contained in:
dal 2025-04-02 14:46:28 -06:00
parent 7e982c3653
commit 021dbd2fa1
No known key found for this signature in database
GPG Key ID: 16F4B0E1E9F61122
7 changed files with 118 additions and 50 deletions

View File

@ -109,6 +109,50 @@ pub enum Error {
- Keep library-specific test helpers in the library
- Use workspace-defined test macros if available
#### Database Integration Tests
For tests that require database access, the preferred approach is to use automatic pool initialization:
```rust
// In tests/mod.rs
use database::pool::init_pools;
use lazy_static::lazy_static;
lazy_static! {
// Initialize test environment once across all tests
static ref TEST_ENV: () = {
let rt = tokio::runtime::Runtime::new().unwrap();
if let Err(e) = rt.block_on(init_pools()) {
panic!("Failed to initialize test pools: {}", e);
}
println!("✅ Test environment initialized");
};
}
#[ctor::ctor]
fn init_test_env() {
lazy_static::initialize(&TEST_ENV);
}
```
Then write normal tests without explicit initialization:
```rust
// In your test file
#[tokio::test]
async fn test_database_functionality() -> Result<()> {
// Pool is already initialized - just get it
let pool = database::pool::get_pg_pool();
// Your test code here
Ok(())
}
```
This pattern ensures:
- Database pools are initialized exactly once at test startup
- All tests can access the same pool without manual initialization
- Test code remains clean without initialization boilerplate
### 5. Documentation
- Follow workspace documentation style
- Link to related workspace documentation

View File

@ -30,5 +30,4 @@ reqwest = { workspace = true }
[dev-dependencies]
tokio-test = { workspace = true }
testkit = { path = "../../testkit" }
tokio-test = { workspace = true }

View File

@ -1,45 +0,0 @@
use anyhow::Result;
#[tokio::test]
async fn test_database_connection() -> Result<()> {
// Get the database pool from testkit
let pool = testkit::get_pg_pool();
// Test the connection by getting a connection from the pool
let conn = pool.get().await?;
// If we got here without errors, the connection is working
Ok(())
}
#[tokio::test]
async fn test_with_isolation() -> Result<()> {
// Get a unique test ID for data isolation
let test_id = testkit::test_id();
// Get database pool
let pool = testkit::get_pg_pool();
// Get a DB connection
let mut conn = pool.get().await?;
// Here you would create test data with test_id for isolation
// For example:
// diesel::sql_query("INSERT INTO users (id, email, test_id) VALUES ($1, $2, $3)")
// .bind::<diesel::sql_types::Uuid, _>(uuid::Uuid::new_v4())
// .bind::<diesel::sql_types::Text, _>("test@example.com")
// .bind::<diesel::sql_types::Text, _>(&test_id)
// .execute(&mut conn)
// .await?;
// Run assertions on the test data
// Clean up after the test
// For example:
// diesel::sql_query("DELETE FROM users WHERE test_id = $1")
// .bind::<diesel::sql_types::Text, _>(&test_id)
// .execute(&mut conn)
// .await?;
Ok(())
}

View File

@ -120,4 +120,33 @@ async fn example_handler(req: PostChatRequest, user: AuthenticatedUser) -> Resul
- Test the full request-response cycle for integration tests
- Use test fixtures for consistent test data
- Run tests with: `cargo test -p handlers`
- Create tests for each handler in the corresponding `tests/` directory
- Create tests for each handler in the corresponding `tests/` directory
### Automatic Test Environment Setup
Integration tests in this library use an automatic database pool initialization system. The environment is set up once when the test module is loaded, eliminating the need for explicit initialization in each test.
Key components:
- `tests/mod.rs` contains the initialization code using `lazy_static` and `ctor`
- Database pools are initialized only once for all tests
- Tests can directly use `get_pg_pool()` without any setup code
Example test:
```rust
use anyhow::Result;
use database::pool::get_pg_pool;
#[tokio::test]
async fn test_handler_functionality() -> Result<()> {
// Database pool is already initialized
let pool = get_pg_pool();
// Test code here using the pool
Ok(())
}
```
To add new test modules, simply:
1. Create a new module in the `tests/` directory
2. Add it to the module declarations in `tests/mod.rs`
3. Write standard async tests using `#[tokio::test]`

View File

@ -39,4 +39,6 @@ dashmap = "5.5.3"
[dev-dependencies]
tokio-test = { workspace = true }
mockall = { workspace = true }
dotenv = { workspace = true }
dotenv = { workspace = true }
lazy_static.workspace = true
ctor = "0.4.1"

View File

@ -1,8 +1,22 @@
use anyhow::Result;
use database::pool::get_pg_pool;
// Just a regular tokio test - environment is initialized automatically
#[tokio::test]
async fn test_placeholder() -> Result<()> {
// This is a placeholder test
// Verify we can access the database pool without explicit initialization
let _pool = get_pg_pool();
assert!(true);
Ok(())
}
// Another test - will share the same initialized environment
#[tokio::test]
async fn test_another_test() -> Result<()> {
// Uses the same pool that was initialized once for all tests
let _pool = get_pg_pool();
assert!(true);
Ok(())
}

View File

@ -1,2 +1,27 @@
use database::pool::init_pools;
use lazy_static::lazy_static;
lazy_static! {
// Initialize test environment once across all tests
static ref TEST_ENV: () = {
// Create a runtime for initialization
let rt = tokio::runtime::Runtime::new().unwrap();
// Initialize pools
if let Err(e) = rt.block_on(init_pools()) {
panic!("Failed to initialize test pools: {}", e);
}
println!("✅ Test environment initialized");
};
}
// This constructor runs when the test binary loads
#[ctor::ctor]
fn init_test_env() {
// Force lazy_static initialization
lazy_static::initialize(&TEST_ENV);
}
// Test modules
pub mod dashboards;