postgres

package
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Sep 21, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

Documentation

Overview

Package postgres gives an integration test a real, migrated, empty PostgreSQL database of its own.

Design

One Postgres container is started per test binary (per image) with testcontainers-go and shared by every test in it. Migrations are applied once, into a template database; each test then gets its own database made with CREATE DATABASE ... TEMPLATE .... Copying a template is a file copy inside Postgres rather than a replay of the migration history, so the cost of setting up a test stays constant as the number of migrations grows.

Every database gets a unique name, so tests may call t.Parallel freely. The database is dropped WITH (FORCE) when the test ends, even if the test leaked connections.

Usage

func TestMain(m *testing.M) {
	code := m.Run()
	_ = postgres.Cleanup() // optional: stop the container right away
	os.Exit(code)
}

func TestSomething(t *testing.T) {
	t.Parallel()

	db := postgres.New(t, postgres.WithMigrationsDir("../../migrations"))

	// db.DB is a *sqlx.DB and db.SQL a *sql.DB on an empty, fully
	// migrated database. db.URL is its connection string, for handing
	// to a subprocess or to a different driver.
	var n int
	if err := db.DB.Get(&n, "SELECT count(*) FROM users"); err != nil {
		t.Fatal(err)
	}
}

The migrations directory is required. A relative path is resolved against the working directory of the test binary, which `go test` sets to the directory of the package under test.

Migration bookkeeping table

sql-migrate records applied migrations in a table. Its Go API defaults to "gorp_migrations", while its CLI reads the table name from dbconfig.yml. If the two disagree, the tests and the CLI keep separate bookkeeping and disagree about what has been applied. New therefore defaults to "migrations", the name most dbconfig.yml files use; set WithMigrationsTable to whatever the `table:` key of your dbconfig.yml says. The table is configured per migration run, so sql-migrate's global migrate.SetTable setting is neither needed nor modified.

Driver

The package registers and uses github.com/lib/pq (driver name "postgres"). URL is a standard postgres:// URL, so code that prefers pgx can open it with sql.Open("pgx", db.URL) after importing github.com/jackc/pgx/v5/stdlib.

Index

Constants

View Source
const (
	// DefaultImage is the Postgres image used unless WithImage says otherwise.
	DefaultImage = "postgres:16-alpine"

	// DefaultMigrationsTable is the sql-migrate bookkeeping table New uses
	// unless WithMigrationsTable says otherwise.
	DefaultMigrationsTable = "migrations"
)

Variables

This section is empty.

Functions

func Cleanup

func Cleanup() error

Cleanup terminates the shared containers. Call it from TestMain to remove them as soon as the tests finish; otherwise testcontainers' reaper removes them after the test binary exits. A later New starts a fresh container.

Types

type ConnectionInfo deprecated

type ConnectionInfo struct {
	Host     string
	Port     string
	User     string
	Password string
	DBName   string
	SSLMode  string
}

ConnectionInfo contains database connection details.

Deprecated: use TestDB.URL, which carries the same details.

func (ConnectionInfo) ConnectionString

func (c ConnectionInfo) ConnectionString() string

ConnectionString returns a PostgreSQL connection string.

type Option added in v0.0.2

type Option func(*config)

Option configures New.

func WithImage added in v0.0.2

func WithImage(image string) Option

WithImage sets the Postgres image to run, DefaultImage by default. Tests asking for different images get different containers. The image must be Postgres 13 or newer, which DROP DATABASE ... WITH (FORCE) requires.

func WithMigrationsDir added in v0.0.2

func WithMigrationsDir(dir string) Option

WithMigrationsDir sets the directory of sql-migrate migrations to apply. It is required: a library cannot guess where its consumer keeps migrations. A relative path is resolved against the working directory.

func WithMigrationsTable added in v0.0.2

func WithMigrationsTable(table string) Option

WithMigrationsTable sets the table sql-migrate records applied migrations in. It defaults to DefaultMigrationsTable ("migrations") and should match the `table:` key of your dbconfig.yml.

type Options deprecated

type Options struct {
	// MigrationsDir is the path to the migrations directory. Unlike New,
	// NewTestDB treats an empty value as "apply no migrations".
	MigrationsDir string

	// MigrationsTable is the sql-migrate bookkeeping table. Empty keeps the
	// historical behaviour of using sql-migrate's global setting
	// ("gorp_migrations" unless migrate.SetTable was called).
	MigrationsTable string
}

Options configures NewTestDB.

Deprecated: use New with WithMigrationsDir and WithMigrationsTable.

type TestDB

type TestDB struct {
	// DB is connected to the test's database.
	DB *sqlx.DB

	// SQL is the *sql.DB underlying DB, for code that does not use sqlx.
	SQL *sql.DB

	// URL is the connection string of the database, for handing it to a
	// subprocess or opening it with a different driver.
	URL string

	// ConnInfo holds the same connection details as URL, split into fields.
	//
	// Deprecated: use URL.
	ConnInfo ConnectionInfo
	// contains filtered or unexported fields
}

TestDB is one test's own database.

func New added in v0.0.2

func New(t testing.TB, opts ...Option) *TestDB

New returns an empty database with every migration applied, for the duration of the test, and registers t.Cleanup to drop it. It fails the test rather than returning an error: a test cannot carry on without its database.

func NewTestDB deprecated

func NewTestDB(opts Options) (*TestDB, error)

NewTestDB creates a new isolated test database with migrations applied. The caller must Close it.

It shares the container and the template databases with New, so it gets the same speed-up, but it returns an error instead of failing a test and does not register any cleanup.

Deprecated: use New, which fails the test on error and drops the database when the test ends.

func (*TestDB) Close

func (t *TestDB) Close() error

Close disconnects from the database and drops it. New registers it with t.Cleanup, so a test does not normally call it. Calling it again is a no-op.

Jump to

Keyboard shortcuts

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