Advanced
Testing
Unit tests, integration tests with testcontainers, and browser-based E2E.
HAMR projects come pre-wired for three layers of testing: fast unit tests with the standard library and testify, integration tests against a real PostgreSQL spun up by testcontainers-go, and browser-driven end-to-end tests via go-rod.
Unit tests
internal/service/auth_test.go
package service_test
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/yourname/myapp/internal/service"
)
func TestRegister(t *testing.T) {
store := newFakeStore()
svc := service.NewAuthService(store)
user, err := svc.Register(context.Background(), "alice@example.com", "secret123!", "Alice")
assert.NoError(t, err)
assert.Equal(t, "alice@example.com", user.Email)
}Integration tests
Use testcontainers-go to spin up a real Postgres for each test run. HAMR projects include a helper that starts the container, runs migrations, and returns a connected store.
integration test
func TestBookRepo(t *testing.T) {
store, cleanup := testdb.NewStore(t)
defer cleanup()
err := store.CreateBook(ctx, &repo.Book{Title: "The Hobbit"})
assert.NoError(t, err)
books, err := store.AllBooks(ctx)
assert.NoError(t, err)
assert.Len(t, books, 1)
}End-to-end tests
HAMR's e2e-go/ directory contains browser-driven tests using go-rod. They run against your real binary serving real templates against a real database.
e2e-go/auth_test.go
func TestLoginFlow(t *testing.T) {
app := harness.Start(t)
defer app.Stop()
page := app.Browser.MustPage(app.URL("/login"))
page.MustElement("#email").MustInput("alice@example.com")
page.MustElement("#password").MustInput("secret123!")
page.MustElement("button[type=submit]").MustClick()
page.MustWaitNavigation()
assert.Contains(t, page.MustInfo().URL, "/dashboard")
}Running tests
Makefile targets
make test # unit tests
make e2e # E2E tests (containerized)
make e2e-local # E2E tests against your local dev serverTest helpers come for free
Every HAMR project ships with reusable test harnesses for Postgres, HTTP servers, and browser sessions. You should rarely need to wire setup code by hand.