dbtest

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 11, 2026 License: MIT Imports: 16 Imported by: 0

README

dbtest

import "github.com/brpaz/lib-go/db/dbtest"

Package dbtest provides lightweight test helpers for code built on github.com/brpaz/lib\-go/db.

Transactions

WithTx opens a transaction on an existing *gorm.DB and rolls it back when the test ends, giving each test a clean slate:

func TestCreateUser(t *testing.T) {
    tx := dbtest.WithTx(t, gormDB)
    svc := user.NewService(tx)
    // any writes are rolled back when t ends
}
PostgreSQL

NewPostgresContainer starts an ephemeral PostgreSQL instance via Testcontainers:

func TestSomething(t *testing.T) {
    pg, err := dbtest.NewPostgresContainer(context.Background())
    require.NoError(t, err)
    pg.Cleanup(t) // terminates the container when t ends
}

For a package-scoped container shared across all tests, set a package-level variable from TestMain and use PostgresContainer.NewIsolatedDB per test:

var testPG *dbtest.PostgresContainer

func TestMain(m *testing.M) {
    var err error
    testPG, err = dbtest.NewPostgresContainer(context.Background())
    if err != nil { log.Fatal(err) }
    code := m.Run()
    testPG.Terminate(context.Background())
    os.Exit(code)
}

func TestSomething(t *testing.T) {
    db := testPG.NewIsolatedDB(t) // fresh database, dropped on test end
}

Use MigratePostgres to apply goose SQL migrations to a database before running tests against it (the container's default database, or one returned by PostgresContainer.NewIsolatedDB):

//go:embed migrations/*.sql
var migrationsFS embed.FS

pg, err := dbtest.NewPostgresContainer(context.Background())
require.NoError(t, err)
require.NoError(t, dbtest.MigratePostgres(context.Background(), pg.DSN, migrationsFS))
SQLite

NewSQLite opens a fresh, isolated in-memory SQLite database — no Docker required. Each call gets its own database, safe for parallel tests:

func TestSomething(t *testing.T) {
    gdb, err := dbtest.NewSQLite()
    require.NoError(t, err)
}

Pass [WithSQLiteMigrations] to apply goose SQL migrations before NewSQLite returns:

//go:embed migrations/*.sql
var migrationsFS embed.FS

gdb, err := dbtest.NewSQLite(dbtest.WithSQLiteMigrations(migrationsFS))

Index

func MigratePostgres

func MigratePostgres(ctx context.Context, dsn string, fsys fs.FS) error

MigratePostgres opens a raw *sql.DB connection to dsn and applies the goose SQL migrations from fsys using the postgres dialect.

Use this against a PostgresContainer.DSN (or a database returned by PostgresContainer.NewIsolatedDB) to prepare a schema before running tests.

func NewSQLite

func NewSQLite(opts ...SQLiteOption) (*gorm.DB, error)

NewSQLite opens a fresh, isolated in-memory SQLite database for use in tests. Each call returns its own database, safe for use in parallel tests.

SQLite in-memory databases only persist for as long as a connection is open, so the returned *gorm.DB is configured with a single connection in its pool to keep the schema and data visible across queries.

func WithTx

func WithTx(t *testing.T, db *gorm.DB) *gorm.DB

WithTx opens a database transaction on db and returns it as a *gorm.DB. The transaction is automatically rolled back when t ends, so each test starts with a clean slate without needing to reset or drop tables.

The returned *gorm.DB is a drop-in replacement for a regular *gorm.DB and can be passed directly to application services and repositories under test.

func TestCreateUser(t *testing.T) {
    tx := dbtest.WithTx(t, gormDB)
    svc := user.NewService(tx)
    // any writes are rolled back when t ends
}

type PostgresContainer

PostgresContainer wraps a Testcontainers PostgreSQL container for use in tests.

type PostgresContainer struct {
    DSN string
    // contains filtered or unexported fields
}

func NewPostgresContainer
func NewPostgresContainer(ctx context.Context, opts ...PostgresOption) (c *PostgresContainer, err error)

NewPostgresContainer starts a PostgreSQL container and returns it. The caller is responsible for terminating it — call PostgresContainer.Cleanup to register automatic termination scoped to a test, or PostgresContainer.Terminate after m.Run() in TestMain.

func (*PostgresContainer) Cleanup
func (c *PostgresContainer) Cleanup(t *testing.T)

Cleanup registers a t.Cleanup hook that terminates the container when t ends. Call this immediately after NewPostgresContainer in per-test usage.

func (*PostgresContainer) NewIsolatedDB
func (c *PostgresContainer) NewIsolatedDB(t *testing.T) *sql.DB

NewIsolatedDB creates a fresh Postgres database on the shared container and returns an open *sql.DB connected to it. The database is dropped when t ends.

Use this in package-scoped container tests to keep each test's schema changes independent without spinning up a new container per test.

func (*PostgresContainer) OpenDB
func (c *PostgresContainer) OpenDB(t *testing.T) *sql.DB

OpenDB opens a *sql.DB connection to the container using the pgx driver. The connection is closed automatically when t ends via t.Cleanup.

func (*PostgresContainer) Terminate
func (c *PostgresContainer) Terminate(ctx context.Context)

Terminate stops the container. Call this after m.Run() returns in TestMain.

type PostgresOption

PostgresOption is a functional option for NewPostgresContainer.

type PostgresOption func(*PostgresOptions)

func WithPostgresContainerOptions
func WithPostgresContainerOptions(opts ...testcontainers.ContainerCustomizer) PostgresOption

WithPostgresContainerOptions appends additional Testcontainers customizers (e.g. custom wait strategies, env vars, mounts) to the container request.

func WithPostgresDatabase
func WithPostgresDatabase(name string) PostgresOption

WithPostgresDatabase overrides the default database name. Defaults to "testdb".

func WithPostgresImage
func WithPostgresImage(image string) PostgresOption

WithPostgresImage overrides the Postgres image used by the container. Defaults to "postgres:18-alpine".

func WithPostgresPassword
func WithPostgresPassword(password string) PostgresOption

WithPostgresPassword overrides the default Postgres password. Defaults to "postgres".

func WithPostgresUsername
func WithPostgresUsername(name string) PostgresOption

WithPostgresUsername overrides the default Postgres username. Defaults to "postgres".

type PostgresOptions

PostgresOptions configures NewPostgresContainer.

type PostgresOptions struct {
    Image         string
    Database      string
    Username      string
    Password      string
    ContainerOpts []testcontainers.ContainerCustomizer
}

type SQLiteOption

SQLiteOption is a functional option for NewSQLite.

type SQLiteOption func(*SQLiteOptions)

type SQLiteOptions

SQLiteOptions configures NewSQLite.

type SQLiteOptions struct {
}

Generated by gomarkdoc

Documentation

Overview

Package dbtest provides lightweight test helpers for code built on github.com/brpaz/lib-go/db.

Transactions

WithTx opens a transaction on an existing *gorm.DB and rolls it back when the test ends, giving each test a clean slate:

func TestCreateUser(t *testing.T) {
    tx := dbtest.WithTx(t, gormDB)
    svc := user.NewService(tx)
    // any writes are rolled back when t ends
}

PostgreSQL

NewPostgresContainer starts an ephemeral PostgreSQL instance via Testcontainers:

func TestSomething(t *testing.T) {
    pg, err := dbtest.NewPostgresContainer(context.Background())
    require.NoError(t, err)
    pg.Cleanup(t) // terminates the container when t ends
}

For a package-scoped container shared across all tests, set a package-level variable from TestMain and use PostgresContainer.NewIsolatedDB per test:

var testPG *dbtest.PostgresContainer

func TestMain(m *testing.M) {
    var err error
    testPG, err = dbtest.NewPostgresContainer(context.Background())
    if err != nil { log.Fatal(err) }
    code := m.Run()
    testPG.Terminate(context.Background())
    os.Exit(code)
}

func TestSomething(t *testing.T) {
    db := testPG.NewIsolatedDB(t) // fresh database, dropped on test end
}

Use MigratePostgres to apply goose SQL migrations to a database before running tests against it (the container's default database, or one returned by PostgresContainer.NewIsolatedDB):

//go:embed migrations/*.sql
var migrationsFS embed.FS

pg, err := dbtest.NewPostgresContainer(context.Background())
require.NoError(t, err)
require.NoError(t, dbtest.MigratePostgres(context.Background(), pg.DSN, migrationsFS))

SQLite

NewSQLite opens a fresh, isolated in-memory SQLite database — no Docker required. Each call gets its own database, safe for parallel tests:

func TestSomething(t *testing.T) {
    gdb, err := dbtest.NewSQLite()
    require.NoError(t, err)
}

Pass [WithSQLiteMigrations] to apply goose SQL migrations before NewSQLite returns:

//go:embed migrations/*.sql
var migrationsFS embed.FS

gdb, err := dbtest.NewSQLite(dbtest.WithSQLiteMigrations(migrationsFS))

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func MigratePostgres

func MigratePostgres(ctx context.Context, dsn string, fsys fs.FS) error

MigratePostgres opens a raw *sql.DB connection to dsn and applies the goose SQL migrations from fsys using the postgres dialect.

Use this against a [PostgresContainer.DSN] (or a database returned by PostgresContainer.NewIsolatedDB) to prepare a schema before running tests.

func NewSQLite

func NewSQLite(opts ...SQLiteOption) (*gorm.DB, error)

NewSQLite opens a fresh, isolated in-memory SQLite database for use in tests. Each call returns its own database, safe for use in parallel tests.

SQLite in-memory databases only persist for as long as a connection is open, so the returned *gorm.DB is configured with a single connection in its pool to keep the schema and data visible across queries.

func WithTx

func WithTx(t *testing.T, db *gorm.DB) *gorm.DB

WithTx opens a database transaction on db and returns it as a *gorm.DB. The transaction is automatically rolled back when t ends, so each test starts with a clean slate without needing to reset or drop tables.

The returned *gorm.DB is a drop-in replacement for a regular *gorm.DB and can be passed directly to application services and repositories under test.

func TestCreateUser(t *testing.T) {
    tx := dbtest.WithTx(t, gormDB)
    svc := user.NewService(tx)
    // any writes are rolled back when t ends
}

Types

type PostgresContainer

type PostgresContainer struct {
	DSN string
	// contains filtered or unexported fields
}

PostgresContainer wraps a Testcontainers PostgreSQL container for use in tests.

func NewPostgresContainer

func NewPostgresContainer(ctx context.Context, opts ...PostgresOption) (c *PostgresContainer, err error)

NewPostgresContainer starts a PostgreSQL container and returns it. The caller is responsible for terminating it — call PostgresContainer.Cleanup to register automatic termination scoped to a test, or PostgresContainer.Terminate after m.Run() in TestMain.

func (*PostgresContainer) Cleanup

func (c *PostgresContainer) Cleanup(t *testing.T)

Cleanup registers a t.Cleanup hook that terminates the container when t ends. Call this immediately after NewPostgresContainer in per-test usage.

func (*PostgresContainer) NewIsolatedDB

func (c *PostgresContainer) NewIsolatedDB(t *testing.T) *sql.DB

NewIsolatedDB creates a fresh Postgres database on the shared container and returns an open *sql.DB connected to it. The database is dropped when t ends.

Use this in package-scoped container tests to keep each test's schema changes independent without spinning up a new container per test.

func (*PostgresContainer) OpenDB

func (c *PostgresContainer) OpenDB(t *testing.T) *sql.DB

OpenDB opens a *sql.DB connection to the container using the pgx driver. The connection is closed automatically when t ends via t.Cleanup.

func (*PostgresContainer) Terminate

func (c *PostgresContainer) Terminate(ctx context.Context)

Terminate stops the container. Call this after m.Run() returns in TestMain.

type PostgresOption

type PostgresOption func(*PostgresOptions)

PostgresOption is a functional option for NewPostgresContainer.

func WithPostgresContainerOptions

func WithPostgresContainerOptions(opts ...testcontainers.ContainerCustomizer) PostgresOption

WithPostgresContainerOptions appends additional Testcontainers customizers (e.g. custom wait strategies, env vars, mounts) to the container request.

func WithPostgresDatabase

func WithPostgresDatabase(name string) PostgresOption

WithPostgresDatabase overrides the default database name. Defaults to "testdb".

func WithPostgresImage

func WithPostgresImage(image string) PostgresOption

WithPostgresImage overrides the Postgres image used by the container. Defaults to "postgres:18-alpine".

func WithPostgresPassword

func WithPostgresPassword(password string) PostgresOption

WithPostgresPassword overrides the default Postgres password. Defaults to "postgres".

func WithPostgresUsername

func WithPostgresUsername(name string) PostgresOption

WithPostgresUsername overrides the default Postgres username. Defaults to "postgres".

type PostgresOptions

type PostgresOptions struct {
	Image         string
	Database      string
	Username      string
	Password      string
	ContainerOpts []testcontainers.ContainerCustomizer
}

PostgresOptions configures NewPostgresContainer.

type SQLiteOption

type SQLiteOption func(*SQLiteOptions)

SQLiteOption is a functional option for NewSQLite.

type SQLiteOptions

type SQLiteOptions struct {
}

SQLiteOptions configures NewSQLite.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL