Testing and deployment
Verify stored data, preserved schema and repeat execution on the actual target engine.
Examples use Classic and Fluent tabs. Your choice follows you through the manual.
Test a migration lifecycle
Create a disposable database, apply the migration, check the schema and rows, run to the same target again, then downgrade and verify the intended reverse. Both authoring styles use the same runner. This fragment assumes an initialized runner whose migration set creates Users.
Classic
runner.MigrateToLastVersion();
if (!provider.TableExists("Users")) throw new Exception("Users missing");
runner.MigrateToLastVersion();
runner.MigrateTo(0);
if (provider.TableExists("Users")) throw new Exception("Users was not removed");Fluent
runner.MigrateToLastVersion();
if (!provider.TableExists("Users")) throw new Exception("Users missing");
runner.MigrateToLastVersion();
runner.MigrateTo(0);
if (provider.TableExists("Users")) throw new Exception("Users was not removed");Shared host · both styles
What to assert
Test defaults by omitting a value, and nullability by explicitly sending NULL. Verify composite-key order, foreign-key actions and constraint names. After a SQLite rebuild check real rows, collations, supported indexes/triggers and identity high-water state. Test failure paths as well as successful SQL generation.
Use representative production-sized data to measure lock duration and backfill cost. A passing SQL-string assertion does not establish that a database accepts a command or preserves its semantics.
Repository checks
Build with dotnet build Migrator.slnx, then use .github/scripts/test.ps1 -Database Unit or SQLite for local suites. The live-engine guide gives the external database setup. Homepage CI results include commit provenance and skipped/missing-suite status.
Production rollout
Keep applied migrations immutable, review SQL and explicit reverse behavior, and serialize competing deploys. Validate against a restored database before making a breaking change. Plan application compatibility around expand/backfill/contract phases. Treat post-commit callback failures as durable migrations requiring follow-up handling.