Examples
Here are some practical examples of how to use embedded-postgres
in common testing scenarios.
Example 1: Testing Database Migrations with Goose
You can use embedded-postgres
to create a real database to test your schema migrations.
import (
"testing"
embeddedpostgres "github.com/fergusstrange/embedded-postgres"
"github.com/jmoiron/sqlx"
_ "github.com/lib/pq"
"github.com/pressly/goose/v3"
)
func Test_GooseMigrations(t *testing.T) {
// Start the database
database := embeddedpostgres.NewDatabase()
if err := database.Start(); err != nil {
t.Fatal(err)
}
defer database.Stop()
// Connect to the database
db, err := sqlx.Connect("postgres", "host=localhost port=5432 user=postgres password=postgres dbname=postgres sslmode=disable")
if err != nil {
t.Fatal(err)
}
// Run migrations
if err := goose.Up(db.DB, "./migrations"); err != nil {
t.Fatal(err)
}
// You can now verify that the schema was created correctly
// by querying the tables, columns, etc.
}
Example 2: Testing an HTTP Handler
This example shows how to test a web application's HTTP handler that depends on a database.
import (
"net/http"
"net/http/httptest"
"testing"
embeddedpostgres "github.com/fergusstrange/embedded-postgres"
// Assume NewApp() sets up your application and routes
)
func Test_SimpleHttpWebApp(t *testing.T) {
// Start the database for the test
database := embeddedpostgres.NewDatabase()
if err := database.Start(); err != nil {
t.Fatal(err)
}
defer database.Stop()
// Your application setup function (NewApp) would internally
// connect to the database we just started.
app := NewApp() // This function needs to be adapted to connect to the test DB.
request := httptest.NewRequest("GET", "/beer-catalogue?name=Punk%20IPA", nil)
recorder := httptest.NewRecorder()
app.router.ServeHTTP(recorder, request)
if recorder.Code != http.StatusOK {
t.Fatalf("expected 200 but receieved %d", recorder.Code)
}
expectedPayload := `[{"id":1,"name":"Punk IPA","consumed":true,"rating":68.29}]`
actualPayload := recorder.Body.String()
if actualPayload != expectedPayload {
t.Fatalf("expected %s but receieved %s", expectedPayload, actualPayload)
}
}
Example 3: Running Multiple Test Cases Against a Single Database
For faster tests, you can start the database once and run multiple sub-tests against it. You'll need to be careful to clean up or reset state between tests.
import (
"fmt"
"reflect"
"testing"
embeddedpostgres "github.com/fergusstrange/embedded-postgres"
"github.com/jmoiron/sqlx"
)
func Test_ManyTestsAgainstOneDatabase(t *testing.T) {
database := embeddedpostgres.NewDatabase()
if err := database.Start(); err != nil {
t.Fatal(err)
}
defer database.Stop()
db, err := sqlx.Connect("postgres", "host=localhost port=5432 user=postgres password=postgres dbname=postgres sslmode=disable")
if err != nil {
t.Fatal(err)
}
// Optional: apply migrations once before all tests
// goose.Up(db.DB, "./migrations")
tests := []struct {
name string
fn func(t *testing.T, db *sqlx.DB)
}{
{
name: "Test query for existing item",
fn: func(t *testing.T, db *sqlx.DB) {
// test logic here...
},
},
{
name: "Test inserting a new item",
fn: func(t *testing.T, db *sqlx.DB) {
// Ensure cleanup for this specific test case
defer db.Exec("DELETE FROM my_table WHERE name = 'Test Item'")
// test logic here...
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.fn(t, db)
})
}
}