switchy_schema_test_utils 0.3.0

Switchy Schema Test Utils package
docs.rs failed to build switchy_schema_test_utils-0.3.0
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.

Switchy Schema Test Utils

Test utilities for switchy_schema that provide comprehensive migration testing capabilities.

Overview

This package provides testing utilities for validating database migrations:

  • verify_migrations_full_cycle - Basic up/down migration testing
  • verify_migrations_with_state - Migration testing with pre-seeded state
  • verify_migrations_with_mutations - Testing with data mutations between migration steps
  • MigrationTestBuilder - Builder pattern for complex migration scenarios with breakpoints (requires sqlite feature)
  • MigrationSnapshotTest - Schema snapshot comparison testing (requires snapshots feature)
  • assertions module - Database schema and state assertion helpers (requires sqlite feature)
  • create_empty_in_memory - Create an in-memory SQLite database for testing (requires sqlite feature)

Features

  • Database Support: SQLite support via feature flags (additional databases planned)
  • Comprehensive Testing: Full migration lifecycle validation
  • State Preservation: Verify data integrity during migrations
  • Mutation Testing: Test against various database states and scenarios
  • Async Support: Full async/await support for modern Rust applications
  • Snapshot Testing: Schema snapshot comparison (optional snapshots feature)

Usage

Add to your Cargo.toml:

[dev-dependencies]
switchy_schema_test_utils = { workspace = true, features = ["sqlite"] }

Creating a Test Database

Use create_empty_in_memory to create an in-memory SQLite database for testing (requires sqlite feature):

use switchy_schema_test_utils::create_empty_in_memory;

#[tokio::test]
async fn test_example() {
    let db = create_empty_in_memory().await.unwrap();
    // Use db for migration testing...
}

Basic Migration Testing

use switchy_schema_test_utils::verify_migrations_full_cycle;

#[tokio::test]
async fn test_migrations() {
    let db = /* your database connection */;
    let migrations = vec![/* your migrations */];
    verify_migrations_full_cycle(db, migrations).await.unwrap();
}

State Preservation Testing

use switchy_schema_test_utils::verify_migrations_with_state;

#[tokio::test]
async fn test_migrations_with_data() {
    let db = /* your database connection */;
    let migrations = vec![/* your migrations */];
    verify_migrations_with_state(
        db,
        migrations,
        |db| Box::pin(async move {
            // Setup initial state before migrations
            db.exec_raw("INSERT INTO existing_table (id) VALUES (1)").await?;
            Ok(())
        })
    ).await.unwrap();
}

Mutation Testing

use switchy_schema_test_utils::verify_migrations_with_mutations;
use switchy_schema_test_utils::mutations::MutationBuilder;

#[tokio::test]
async fn test_migrations_comprehensive() {
    let db = /* your database connection */;
    let migrations = vec![/* your migrations */];
    let mutations = MutationBuilder::new()
        .add_mutation("001_create_users", "INSERT INTO users (name) VALUES ('test')")
        .build();
    verify_migrations_with_mutations(
        db,
        migrations,
        mutations,
    ).await.unwrap();
}

Advanced: Migration Test Builder (requires sqlite feature)

use switchy_schema_test_utils::MigrationTestBuilder;

#[tokio::test]
async fn test_data_migration() {
    let db = /* your database connection */;
    let migrations = vec![/* your migrations */];

    MigrationTestBuilder::new(migrations)
        .with_data_before("002_migrate_data", |db| {
            Box::pin(async move {
                // Insert test data before the migration runs
                db.exec_raw("INSERT INTO old_table (value) VALUES ('test')").await?;
                Ok(())
            })
        })
        .with_data_after("002_migrate_data", |db| {
            Box::pin(async move {
                // Verify migration transformed data correctly
                db.exec_raw("SELECT * FROM new_table WHERE value = 'test'").await?;
                Ok(())
            })
        })
        .run(db)
        .await
        .unwrap();
}

Schema and State Assertions (requires sqlite feature)

use switchy_schema_test_utils::assertions::*;

#[tokio::test]
async fn test_migration_schema() {
    let db = /* your database connection */;

    // Verify table existence
    assert_table_exists(db, "users").await.unwrap();
    assert_table_not_exists(db, "old_table").await.unwrap();

    // Verify columns
    assert_column_exists(db, "users", "email", "TEXT").await.unwrap();

    // Verify data state
    assert_row_count(db, "users", 5).await.unwrap();
    assert_row_count_min(db, "posts", 10).await.unwrap();

    // Verify migrations applied
    assert_migrations_applied(db, &["001_initial", "002_add_users"]).await.unwrap();
}

Snapshot Testing (requires snapshots feature)

use switchy_schema_test_utils::MigrationSnapshotTest;

#[tokio::test]
async fn test_migration_snapshots() {
    MigrationSnapshotTest::new("my_migration_test")
        .migrations_dir("migrations")
        .expected_tables(vec!["users".to_string(), "posts".to_string()])
        .assert_schema(true)
        .assert_sequence(true)
        .run()
        .await
        .unwrap();
}

Cargo Features

  • sqlite - Enable SQLite support (included in default features)
  • snapshots - Enable schema snapshot testing capabilities
  • decimal - Enable decimal type support (included in default features)
  • uuid - Enable UUID type support (included in default features)
  • fail-on-warnings - Treat warnings as errors during compilation

Examples

See the examples/ directory in the parent switchy_schema package for complete working examples of each testing utility.