freezeray generate
Generate FreezeRay artifacts (fixtures, schema tests, or migration tests) with granular control over the workflow.
Synopsis
freezeray generate < SUBCOMMAN D > [OPTIONS]
# Short alias
freezeray g < SUBCOMMAN D > [OPTIONS]
Description
The generate command provides granular operations for creating FreezeRay artifacts separately.
Most important: Use generate migration-tests when starting work on a new schema version. This lets you write and test migrations as you develop.
The other subcommands (fixtures, schema-tests) are rarely needed because freeze handles them automatically.
Subcommands
migration-tests - Generate migration tests ⭐
freezeray generate migration-tests --from-schema < VERSIO N > --to-schema < VERSIO N >
Generates a migration test file that validates data migration between two schema versions.
This is the primary use case for the generate command.
See detailed documentation →
fixtures - Generate frozen fixtures (Advanced)
freezeray generate fixtures --schema < VERSIO N >
Generates frozen SwiftData fixtures for a specific schema version.
Rarely needed: freeze does this automatically.
See detailed documentation →
schema-tests - Generate drift tests (Advanced)
freezeray generate schema-tests --schema < VERSIO N >
Generates a drift test file that validates a frozen schema hasn’t changed.
Rarely needed: freeze does this automatically.
See detailed documentation →
Why Use generate migration-tests?
The Correct Workflow
Migration tests should be created when you start working on a new schema version, not after:
# 1. Freeze V2
freezeray freeze 2.0.0
# 2. Generate migration test WHEN STARTING V3 work
freezeray generate migration-tests --from-schema 2.0.0 --to-schema 3.0.0
# 3. Edit the generated test, add custom assertions
# 4. Implement V3 schema + migration
# 5. Iterate: run test → fix migration → run test (⌘U)
# 6. When ready, freeze V3
freezeray freeze 3.0.0
This lets you develop with the migration test as you build the new schema.
Key insight: freeze does NOT generate migration tests. You must explicitly run generate migration-tests when starting work on a new schema version.
generate fixtures
Generate frozen fixtures for a specific schema version.
Synopsis
freezeray generate fixtures --schema < VERSIO N > [OPTIONS]
Description
Generates frozen SwiftData fixtures by:
Discovering the @FreezeSchema(version: "X.Y.Z") annotation
Running a freeze test in iOS Simulator
Extracting fixtures from /tmp to FreezeRay/Fixtures/<VERSION>/
Arguments
--schema <VERSION>, -s <VERSION>
Required. The schema version to freeze (e.g., “1.0.0”).
Must match a @FreezeSchema annotation in your source code:
@FreezeSchema (version : "3.0.0" )
enum AppSchemaV3 : VersionedSchema {
// ...
}
Options
--simulator <NAME>
Default: iPhone 17
iOS Simulator to use for freezing:
freezeray generate fixtures --schema 3.0.0 --simulator "iPhone 15 Pro"
--scheme <NAME>
Default: Auto-detected
Xcode scheme to build:
freezeray generate fixtures --schema 3.0.0 --scheme MyApp
--force
Overwrite existing fixtures (dangerous!):
freezeray generate fixtures --schema 3.0.0 --force
Only use --force during development before shipping to production. Overwriting frozen fixtures breaks immutability.
--output <PATH>
Default: FreezeRay/Fixtures
Custom output directory:
freezeray generate fixtures --schema 3.0.0 --output /custom/path
--config <PATH>
Path to FreezeRay.yaml config file (experimental):
freezeray generate fixtures --schema 3.0.0 --config .freezeray.yml
What Gets Created
FreezeRay/Fixtures/3.0.0/
├── App-3.0.0.sqlite # Frozen SQLite database
├── App-3.0.0.sqlite-shm # SQLite shared memory file
├── schema-3.0.0.sql # SQL DDL statements
├── schema-3.0.0.json # Human-readable schema metadata
├── schema-3.0.0.sha256 # SHA256 checksum for drift detection
└── export_metadata.txt # Timestamp and version info
Examples
Basic usage
freezeray generate fixtures --schema 3.0.0
Output:
🔍 Generating fixtures for schema version 3.0.0...
📱 Running freeze test in simulator (iPhone 17)...
📦 Extracting fixtures from simulator...
✅ Generated fixtures: FreezeRay/Fixtures/3.0.0/
- App-3.0.0.sqlite
- schema-3.0.0.sql
- schema-3.0.0.json
- schema-3.0.0.sha256
- export_metadata.txt
- App-3.0.0.sqlite-shm
freezeray g fixtures -s 3.0.0
Custom simulator
freezeray generate fixtures --schema 3.0.0 --simulator "iPhone 15"
Common Errors
”No @FreezeSchema found for version X.Y.Z”
Cause: The version doesn’t match any @FreezeSchema annotation.
Fix: Add the annotation to your schema:
@FreezeSchema (version : "3.0.0" )
enum AppSchemaV3 : VersionedSchema {
// ...
}
“Fixtures already exist”
Cause: Fixtures for this version already exist.
Solutions:
During development (before shipping):
freezeray generate fixtures --schema 3.0.0 --force
After shipping to production:
# Create new version instead
freezeray generate fixtures --schema 3.0.1
generate schema-tests
Generate drift test for a frozen schema version.
Synopsis
freezeray generate schema-tests --schema < VERSIO N > [OPTIONS]
Description
Generates a drift test file that validates the current schema definition matches the frozen fixtures.
Requirements:
Fixtures must already exist for the specified version
Run freezeray generate fixtures first if needed
Arguments
--schema <VERSION>, -s <VERSION>
Required. The schema version to generate tests for (e.g., “3.0.0”).
Options
--force
Overwrite existing test file:
freezeray generate schema-tests --schema 3.0.0 --force
By default, existing test files are never overwritten (they’re user-owned).
--config <PATH>
Path to config file (experimental):
freezeray generate schema-tests --schema 3.0.0 --config .freezeray.yml
What Gets Created
// FreezeRay/Tests/AppSchemaV3_DriftTests.swift
import Testing
import FreezeRay
@testable import MyApp
/// Drift test for AppSchemaV3 v3.0.0
///
/// This test verifies that the current schema definition matches the frozen fixture.
/// If this test fails, it means the schema has been modified since it was frozen.
///
/// Note: Tests run serially to avoid SwiftData store conflicts
@Suite (. serialized )
struct AppSchemaV3_3_0_0_DriftTests {
@Test ( "AppSchemaV3 v3.0.0 has not drifted" )
func testAppSchemaV3_3_0_0_Drift () throws {
// Call the macro-generated check function
try AppSchemaV3. __freezeray_check_3_0_0 ()
// TODO: Add custom data validation here
// Example:
// - Verify specific model properties exist
// - Check relationship configurations
// - Validate index definitions
}
}
Generated tests use @Suite(.serialized) to prevent parallel execution issues with SwiftData stores.
Examples
Basic usage
freezeray generate schema-tests --schema 3.0.0
Output:
🔍 Generating schema tests for version 3.0.0...
✅ Generated drift test: AppSchemaV3_DriftTests.swift
freezeray g schema-tests -s 3.0.0
Regenerate (overwrite)
freezeray generate schema-tests --schema 3.0.0 --force
Common Errors
”No fixtures found for version X.Y.Z”
Cause: Fixtures don’t exist for the specified version.
Fix: Generate fixtures first:
freezeray generate fixtures --schema 3.0.0
freezeray generate schema-tests --schema 3.0.0
“Test file already exists”
Cause: The drift test file was already generated.
Solutions:
If you want to keep your custom assertions:
# Do nothing - the existing test is yours to maintain
If you want to regenerate:
freezeray generate schema-tests --schema 3.0.0 --force
generate migration-tests
Generate migration test from one schema version to another.
Synopsis
freezeray generate migration-tests --from-schema < VERSIO N > --to-schema < VERSIO N > [OPTIONS]
Description
Generates a migration test file that validates data migration between two schema versions.
This is the key innovation of the generate command: you can create the migration test early in your development workflow, not after the fact.
Requirements:
Fixtures must exist for --from-schema version
@FreezeSchema must exist in code for --to-schema version
SchemaMigrationPlan must have a migration stage between versions
Behavior if test file exists:
Does NOT overwrite (preserves user’s custom assertions)
Prints skip message
Use --force to overwrite
Arguments
--from-schema <VERSION>, -f <VERSION>
Required. Source schema version (e.g., “2.0.0”).
--to-schema <VERSION>, -t <VERSION>
Required. Target schema version (e.g., “3.0.0”).
Options
--force
Overwrite existing test file:
freezeray generate migration-tests -f 2.0.0 -t 3.0.0 --force
Only use --force if you’re sure you want to discard custom assertions you’ve added to the test.
--config <PATH>
Path to config file (experimental):
freezeray generate migration-tests -f 2.0.0 -t 3.0.0 --config .freezeray.yml
What Gets Created
// FreezeRay/Tests/MigrateV2_0_0toV3_0_0_Tests.swift
import Testing
import FreezeRay
@testable import MyApp
/// Migration test from v2.0.0 → v3.0.0
///
/// This test verifies that the migration path between these versions works correctly.
///
/// Note: Tests run serially to avoid SwiftData store conflicts
@Suite (. serialized )
struct MigrateV2_0_0toV3_0_0_Tests {
@Test ( "Migrate v2.0.0 → v3.0.0" )
func testMigrateV2_0_0toV3_0_0 () throws {
// Test the migration using FreezeRayRuntime
try FreezeRayRuntime. testMigration (
from : AppSchemaV2. self ,
to : AppSchemaV3. self ,
migrationPlan : AppMigrations. self
)
// TODO: Add data integrity checks here
// Example:
// - Verify data is preserved during migration
// - Check that new fields have default values
// - Validate relationship updates
// - Ensure no data loss for critical fields
}
}
The generated test includes @Suite(.serialized) to fix parallel execution issues that cause SwiftData store conflicts.
Examples
Basic usage (early workflow)
# When starting V3 development
freezeray generate migration-tests --from-schema 2.0.0 --to-schema 3.0.0
# Edit generated test, add assertions
# Implement V3 schema + migration
# Iterate: run test → fix migration → run test
Output:
🔍 Generating migration test: v2.0.0 → v3.0.0...
✅ Generated migration test: MigrateV2_0_0toV3_0_0_Tests.swift
Edit this file to add custom migration assertions
freezeray g migration-tests -f 2.0.0 -t 3.0.0
Regenerate (overwrite custom assertions)
freezeray generate migration-tests -f 2.0.0 -t 3.0.0 --force
Output:
✅ Generated migration test: MigrateV2_0_0toV3_0_0_Tests.swift
Common Errors
”No fixtures found for version X.Y.Z”
Cause: Source schema fixtures don’t exist.
Fix: Freeze the source version first:
freezeray freeze 2.0.0
freezeray generate migration-tests -f 2.0.0 -t 3.0.0
“No @FreezeSchema found for version X.Y.Z”
Cause: Target schema doesn’t exist in code yet.
Fix: Define the target schema:
@FreezeSchema (version : "3.0.0" )
enum AppSchemaV3 : VersionedSchema {
// ...
}
Then generate the test:
freezeray generate migration-tests -f 2.0.0 -t 3.0.0
“No SchemaMigrationPlan found in codebase”
Cause: You haven’t defined a migration plan.
Fix: Create a migration plan:
enum AppMigrations : SchemaMigrationPlan {
static var schemas: [ any VersionedSchema. Type ] {
[AppSchemaV1. self , AppSchemaV2. self , AppSchemaV3. self ]
}
static var stages: [MigrationStage] {
[migrateV1toV2, migrateV2toV3]
}
static let migrateV2toV3 = MigrationStage. custom (
fromVersion : AppSchemaV2. self ,
toVersion : AppSchemaV3. self ,
willMigrate : nil ,
didMigrate : { context in
// Migration logic
}
)
}
Then generate the test:
freezeray generate migration-tests -f 2.0.0 -t 3.0.0
“Migration test already exists”
Cause: You’ve already generated the migration test.
Solutions:
If you’ve added custom assertions:
# Do nothing - keep your custom test
If you want to start over:
freezeray generate migration-tests -f 2.0.0 -t 3.0.0 --force
Complete Workflow Example
# 1. Ship V2
freezeray freeze 2.0.0
# 2. Start V3 development - generate migration test immediately
freezeray generate migration-tests -f 2.0.0 -t 3.0.0
# 3. Edit generated test, add custom assertions
vim FreezeRay/Tests/MigrateV2_0_0toV3_0_0_Tests.swift
# 4. Implement V3 schema + migration
# (edit schema files, add migration stage)
# 5. Iterate: run tests normally as you develop
# ⌘U in Xcode or:
xcodebuild test -scheme MyApp
# 6. Ship V3
freezeray freeze 3.0.0 # Just generates fixtures + drift test
Key point: You develop with the migration test from the start, not after the fact.
Parallel Execution Fix
All generated tests now use @Suite(.serialized) to prevent parallel execution issues.
Problem (Before)
Migration tests failed when run in parallel (Swift Testing default):
swift test
# ❌ All 3 migration tests fail due to parallel execution
Running individually worked:
swift test --filter MigrateV2toV3
# ✅ Passes
Cause: Tests create/destroy SwiftData stores in temp directories with potential collisions.
Solution (After)
Generated tests now use @Suite(.serialized):
@Suite (. serialized ) // ← Prevents parallel execution
struct MigrateV2_0_0toV3_0_0_Tests {
@Test func testMigrateV2_0_0toV3_0_0 () throws {
// ...
}
}
Now tests work in default harness:
swift test
# ✅ All tests pass
Best Practices
1. Generate Migration Tests Early
Generate the migration test when you start working on the migration:
# ✅ Good: Generate early
freezeray generate migration-tests -f 2.0.0 -t 3.0.0
# Edit test, add assertions
# Implement migration
# Iterate until test passes
# ❌ Bad: Generate after implementing
# (implement migration)
# (write custom test)
freezeray freeze 3.0.0 # Conflict!
2. Never Overwrite User Tests
The generate commands never overwrite existing test files by default:
# First time: creates file
freezeray generate migration-tests -f 2.0.0 -t 3.0.0
# ✅ Generated migration test
# Second time: skips
freezeray generate migration-tests -f 2.0.0 -t 3.0.0
# ⚠️ Migration test already exists (preserving custom assertions)
This protects your custom assertions.
3. Use freeze for Complete Workflow
For most users, freeze is still the recommended command:
# This is still the easiest workflow
freezeray freeze 1.0.0 # Does everything
Only use generate when you need fine-grained control :
Generate migration tests early ✅
Regenerate specific artifacts ✅
Customize the workflow ✅
4. Commit Generated Tests
Generated tests are yours to maintain :
freezeray generate migration-tests -f 2.0.0 -t 3.0.0
# Add custom assertions
vim FreezeRay/Tests/MigrateV2_0_0toV3_0_0_Tests.swift
# Commit with schema changes
git add FreezeRay/Tests/
git commit -m "Add migration test for V2→V3 with data integrity checks"
Test files evolve with your schema, just like any other test.
What freeze Does
The freeze command is simpler than generate - it only creates fixtures and drift tests:
Internally equivalent to:
# 1. Generate fixtures (via simulator)
freezeray generate fixtures --schema 3.0.0
# 2. Generate drift test (if doesn't exist)
freezeray generate schema-tests --schema 3.0.0
That’s it! freeze does NOT touch migration tests.
Migration tests are managed separately with generate migration-tests.
Requirements
Same as freezeray freeze:
macOS 14+
Xcode 15+
iOS Simulator (iPhone 17 recommended)
Project structure:
@FreezeSchema(version: "X.X.X") annotations
Test target for running freeze tests
Xcode project or Swift Package with iOS target
Next Steps
freeze command Learn about the convenience freeze command
Testing Migrations Step-by-step guide for the new migration workflow
Migration Testing Concepts Understand how migration tests work
Drift Detection Learn about schema drift detection