Documentation
¶
Overview ¶
Package testutil provides testing utilities for the database module.
Package testutil provides testing utilities for the database module.
It includes an in-memory SQLite test component that implements both component.Component and testutil.TestComponent interfaces, along with fixture helpers for loading test data and managing database state.
Quick Start ¶
Create a test database with automatic cleanup:
db := testutil.NewComponent()
testutil.T(t).Setup(db)
// Use db.DB() to access *gorm.DB
db.DB().Exec("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)")
Auto-Migration ¶
Register models for automatic migration on Start():
type User struct {
ID uint `gorm:"primarykey"`
Name string
}
db := testutil.NewComponent().WithModels(&User{})
testutil.T(t).Setup(db)
State Management ¶
Use Reset, Snapshot, and Restore for test isolation:
// Reset clears all data testutil.T(t).Reset(db) // Snapshot captures current state snapshot := testutil.T(t).Snapshot(db) // Restore returns to snapshot testutil.T(t).Restore(db, snapshot)
Fixture Helpers ¶
Load test data easily:
MustLoadFixture(t, db.DB(), "users", []map[string]any{
{"name": "Alice", "email": "alice@example.com"},
{"name": "Bob", "email": "bob@example.com"},
})
AssertRowCount(t, db.DB(), "users", 2)
See the README for more examples and best practices.
Migration Driver ¶
MigrationDriver is an in-memory golang-migrate driver fake for exercising migration orchestration (Up/Down/Steps/Reset/Version) without a real database backend. It records the applied version and run count and can be told to fail specific operations, so failure and rollback paths are provable deterministically:
driver := testutil.NewMigrationDriver()
cfg := migration.Config{DB: db, FS: fs, Path: "migrations", Driver: driver.DriverFunc()}
if err := cfg.Up(); err != nil { ... }
// Prove a failing rollback is surfaced, not swallowed:
driver.FailRun()
err := cfg.Down() // wrapped "migrate down" error
Example (BasicUsage) ¶
Example of basic database test component usage
package main
import (
"context"
"fmt"
dbtestutil "github.com/kbukum/gokit/database/testutil"
)
func main() {
// This would be in a test function
// t := &testing.T{} // mocked for example
db := dbtestutil.NewComponent()
// In real tests: testutil.T(t).Setup(db)
db.Start(context.TODO())
defer db.Stop(context.TODO())
// Create table and insert data
db.DB().Exec("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)")
db.DB().Exec("INSERT INTO users (name) VALUES (?)", "Alice")
// Query data
var name string
db.DB().Raw("SELECT name FROM users").Scan(&name)
fmt.Println(name)
}
Output: Alice
Example (Fixtures) ¶
Example of using fixture helpers
package main
import (
"context"
"fmt"
dbtestutil "github.com/kbukum/gokit/database/testutil"
)
func main() {
// In real tests, you would pass *testing.T
db := dbtestutil.NewComponent()
db.Start(context.TODO())
defer db.Stop(context.TODO())
db.DB().Exec("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)")
// Load fixture data
dbtestutil.LoadFixture(db.DB(), "users", []map[string]any{
{"name": "Alice", "email": "alice@example.com"},
{"name": "Bob", "email": "bob@example.com"},
})
count, _ := dbtestutil.CountRows(db.DB(), "users")
fmt.Println("User count:", count)
// Truncate table
dbtestutil.TruncateTable(db.DB(), "users")
count, _ = dbtestutil.CountRows(db.DB(), "users")
fmt.Println("After truncate:", count)
}
Output: User count: 2 After truncate: 0
Example (Reset) ¶
Example of using Reset for test isolation
package main
import (
"context"
"fmt"
dbtestutil "github.com/kbukum/gokit/database/testutil"
)
func main() {
db := dbtestutil.NewComponent()
db.Start(context.TODO())
defer db.Stop(context.TODO())
db.DB().Exec("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)")
db.DB().Exec("INSERT INTO users (name) VALUES (?)", "Alice")
var count int64
db.DB().Raw("SELECT COUNT(*) FROM users").Scan(&count)
fmt.Println("Before reset:", count)
// Reset clears all data
db.Reset(context.TODO())
db.DB().Raw("SELECT COUNT(*) FROM users").Scan(&count)
fmt.Println("After reset:", count)
}
Output: Before reset: 1 After reset: 0
Example (SnapshotRestore) ¶
Example of using Snapshot and Restore
package main
import (
"context"
"fmt"
dbtestutil "github.com/kbukum/gokit/database/testutil"
)
func main() {
db := dbtestutil.NewComponent()
db.Start(context.TODO())
defer db.Stop(context.TODO())
db.DB().Exec("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)")
db.DB().Exec("INSERT INTO users (name) VALUES (?)", "Alice")
// Take snapshot
snapshot, _ := db.Snapshot(context.TODO())
// Modify data
db.DB().Exec("INSERT INTO users (name) VALUES (?)", "Bob")
db.DB().Exec("INSERT INTO users (name) VALUES (?)", "Charlie")
var count int64
db.DB().Raw("SELECT COUNT(*) FROM users").Scan(&count)
fmt.Println("After modifications:", count)
// Restore to snapshot
db.Restore(context.TODO(), snapshot)
db.DB().Raw("SELECT COUNT(*) FROM users").Scan(&count)
fmt.Println("After restore:", count)
}
Output: After modifications: 3 After restore: 1
Example (TestManager) ¶
Example of using TestManager with database component
package main
import (
"context"
"fmt"
dbtestutil "github.com/kbukum/gokit/database/testutil"
"github.com/kbukum/gokit/testutil"
)
func main() {
manager := testutil.NewManager(context.TODO())
db := dbtestutil.NewComponent()
manager.Add(db)
// Start all components
manager.StartAll()
defer manager.Cleanup()
// Use the database
dbComp := manager.Get("database-test").(*dbtestutil.Component)
dbComp.DB().Exec("CREATE TABLE users (id INTEGER PRIMARY KEY)")
exists := dbtestutil.TableExists(dbComp.DB(), "users")
fmt.Println("Table exists:", exists)
}
Output: Table exists: true
Example (WithModels) ¶
Example of using models with auto-migration
package main
import (
"context"
"fmt"
dbtestutil "github.com/kbukum/gokit/database/testutil"
)
func main() {
type User struct {
ID uint `gorm:"primarykey"`
Name string
}
db := dbtestutil.NewComponent().WithModels(&User{})
db.Start(context.TODO())
defer db.Stop(context.TODO())
// Table is automatically created
db.DB().Create(&User{Name: "Bob"})
var user User
db.DB().First(&user)
fmt.Println(user.Name)
}
Output: Bob
Index ¶
- func AssertRowCount(t *testing.T, db *gorm.DB, table string, expected int64)
- func AssertTableEmpty(t *testing.T, db *gorm.DB, table string)
- func CountRows(db *gorm.DB, table string) (int64, error)
- func GetTableNames(db *gorm.DB) ([]string, error)
- func LoadFixture(db *gorm.DB, table string, data []map[string]any) error
- func MustLoadFixture(t *testing.T, db *gorm.DB, table string, data []map[string]any)
- func TableExists(db *gorm.DB, table string) bool
- func TruncateAllTables(db *gorm.DB) error
- func TruncateTable(db *gorm.DB, table string) error
- type Component
- func (c *Component) DB() *gorm.DB
- func (c *Component) Health(ctx context.Context) component.Health
- func (c *Component) Name() string
- func (c *Component) Reset(ctx context.Context) error
- func (c *Component) Restore(ctx context.Context, snap any) error
- func (c *Component) Snapshot(ctx context.Context) (any, error)
- func (c *Component) Start(ctx context.Context) error
- func (c *Component) Stop(ctx context.Context) error
- func (c *Component) WithModels(models ...any) *Component
- type MigrationDriver
- func (d *MigrationDriver) Close() error
- func (d *MigrationDriver) DriverFunc() migration.DriverFunc
- func (d *MigrationDriver) Drop() error
- func (d *MigrationDriver) FailDrop() *MigrationDriver
- func (d *MigrationDriver) FailRun() *MigrationDriver
- func (d *MigrationDriver) FailSetVersion() *MigrationDriver
- func (d *MigrationDriver) Lock() error
- func (d *MigrationDriver) Open(string) (migratedb.Driver, error)
- func (d *MigrationDriver) Run(r io.Reader) error
- func (d *MigrationDriver) Runs() int
- func (d *MigrationDriver) SetVersion(version int, dirty bool) error
- func (d *MigrationDriver) Unlock() error
- func (d *MigrationDriver) Version() (version int, dirty bool, err error)
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AssertRowCount ¶
AssertRowCount fails the test if the table doesn't have the expected row count.
func AssertTableEmpty ¶
AssertTableEmpty fails the test if the table is not empty.
func GetTableNames ¶
GetTableNames returns a list of all non-system tables.
func LoadFixture ¶
LoadFixture loads test data into a table. Data should be a slice of maps where each map represents a row.
func MustLoadFixture ¶
MustLoadFixture loads test data and fails the test on error.
func TableExists ¶
TableExists checks if a table exists in the database.
func TruncateAllTables ¶
TruncateAllTables removes all rows from all tables in the database.
Types ¶
type Component ¶
type Component struct {
// contains filtered or unexported fields
}
Component is a test database component that uses SQLite in-memory. It implements both component.Component and testutil.TestComponent interfaces.
func NewComponent ¶
func NewComponent() *Component
NewComponent creates a new test database component. By default, it uses SQLite in-memory database.
func (*Component) Reset ¶
Reset clears all data from all tables while preserving the schema. This is useful for resetting state between test cases.
func (*Component) Restore ¶
Restore returns the database to a previously captured snapshot state. The snapshot must have been created by the Snapshot method.
func (*Component) Snapshot ¶
Snapshot captures the current state of the database. Returns a snapshot that can be used with Restore to return to this state.
func (*Component) WithModels ¶
WithModels registers models for auto-migration on Start. This is useful when you want the component to automatically create tables for your models during component startup.
type MigrationDriver ¶
type MigrationDriver struct {
// contains filtered or unexported fields
}
MigrationDriver is an in-memory golang-migrate database driver for exercising migration orchestration (Up/Down/Steps/Reset/Version) without a real database backend. It records the applied version and the number of statements run, and can be told to fail specific operations so failure and rollback paths are provable deterministically.
A zero MigrationDriver reports version -1 (no migrations applied); use NewMigrationDriver.
func NewMigrationDriver ¶
func NewMigrationDriver() *MigrationDriver
NewMigrationDriver returns a MigrationDriver with no migrations applied.
func (*MigrationDriver) Close ¶
func (d *MigrationDriver) Close() error
Close implements migratedb.Driver; the fake holds no resources.
func (*MigrationDriver) DriverFunc ¶
func (d *MigrationDriver) DriverFunc() migration.DriverFunc
DriverFunc adapts the fake to a migration.DriverFunc, ignoring the *sql.DB it is handed.
func (*MigrationDriver) Drop ¶
func (d *MigrationDriver) Drop() error
Drop implements migratedb.Driver; it clears the recorded version unless FailDrop is set.
func (*MigrationDriver) FailDrop ¶
func (d *MigrationDriver) FailDrop() *MigrationDriver
FailDrop makes Drop calls fail, simulating a failed schema drop during Reset.
func (*MigrationDriver) FailRun ¶
func (d *MigrationDriver) FailRun() *MigrationDriver
FailRun makes the next and subsequent Run calls fail, simulating a failing migration statement.
func (*MigrationDriver) FailSetVersion ¶
func (d *MigrationDriver) FailSetVersion() *MigrationDriver
FailSetVersion makes SetVersion calls fail, simulating a schema-version write failure.
func (*MigrationDriver) Lock ¶
func (d *MigrationDriver) Lock() error
Lock implements migratedb.Driver.
func (*MigrationDriver) Open ¶
func (d *MigrationDriver) Open(string) (migratedb.Driver, error)
Open implements migratedb.Driver; it returns the receiver unchanged.
func (*MigrationDriver) Run ¶
func (d *MigrationDriver) Run(r io.Reader) error
Run implements migratedb.Driver; it drains the statement and records the run unless FailRun is set.
func (*MigrationDriver) Runs ¶
func (d *MigrationDriver) Runs() int
Runs returns how many migration statements have been applied.
func (*MigrationDriver) SetVersion ¶
func (d *MigrationDriver) SetVersion(version int, dirty bool) error
SetVersion implements migratedb.Driver; it records the version unless FailSetVersion is set.
func (*MigrationDriver) Unlock ¶
func (d *MigrationDriver) Unlock() error
Unlock implements migratedb.Driver.