encore-go-testing — Claude Code skill: tests and install
Write and run Encore Go tests with encore test and Go’s standard testing package. It covers handlers, service calls, databases, errors, and test structure.
npx skills add encoredev/skills --skill encore-go-testing -a claude-code
npx skills add encoredev/skills --skill go-testing -a claude-codeWhat encore-go-testing does
This skill guides tests for Encore Go applications. It uses encore test for the full suite, a selected package, or verbose output, while test files call handlers directly and assert returned values. The examples cover request parameters, service-to-service calls, Encore errors, event publishing, and the function behind a cron job.
It also shows database checks with sqldb.Exec, table-driven cases, and nested tests built with t.Run. Error handling uses errs.Error and its codes. encore test sets up test databases, isolates infrastructure for each test, and handles service dependencies, so the documented workflow does not treat plain go test as the preferred runner.
What it helps with
- write a test for an Encore Go handler
- check an API response with request parameters
- verify database create-and-read flows
- assert an Encore
NotFounderror - organize table-driven and nested tests
Example prompts for the agent
- Write a
*_test.gofile forGetUserand check the response for ID123. - Add a user creation test that stores a record, retrieves it, and checks its email.
- Run the Encore test suite with verbose output using
encore test -v ./....
How to install encore-go-testing
1Skills CLI (Vercel)
npx skills add encoredev/skills --skill encore-go-testing -a claude-codenpx skills add encoredev/skills --skill go-testing -a claude-code2Manually: put the files in place
~/.claude/skills/go-testing/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/go-testing/
1Skills CLI (Vercel)
npx skills add encoredev/skills --skill go-testing -a codex2Manually: put the files in place
.agents/skills/go-testing/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add encoredev/skills --skill go-testing -a cursor2Manually: put the files in place
.cursor/skills/go-testing/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install encoredev/skills go-testing2Manually: put the files in place
.github/skills/go-testing/SKILL.md1Skills CLI (Vercel)
npx skills add encoredev/skills --skill go-testing -a gemini-cli2Platform CLI
gemini skills install https://github.com/encoredev/skills --path encore/go-testingManually: put the files in place
.devin/skills/go-testing/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add encoredev/skills --skill go-testing -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about encore-go-testing
How do I install encore-go-testing in Claude Code?
Run npx skills add encoredev/skills --skill encore-go-testing -a claude-code, then check ~/.claude/skills/go-testing/SKILL.md.
What does encore-go-testing do?
It helps create and run Encore Go tests with encore test and the standard testing package. Its examples cover handlers, databases, service calls, errors, events, and cron logic.
Why use encore test instead of go test for Encore Go?
encore test sets up test databases, provides isolated infrastructure per test, and handles service dependencies.
Source text
SKILL.md · Apache-2.0
---
name: encore-go-testing
description: Write or run automated tests for Encore Go code with `encore test` and the standard library `testing` package. Covers isolated per-test databases, calling handlers directly, and `*testing.T` patterns.
when_to_use: >-
User wants to add/write/fix a test in Go, write a `*_test.go` file, test an endpoint or service, set up `encore test`, configure isolated test databases, write `t.Cleanup`/`t.Helper` for db cleanup, mock external dependencies, or assert on API request/response behaviour. Trigger phrases: "write a Go test", "add tests for", "go test", "encore test", "test the endpoint", "test the service", "integration test", "isolated database".
---
# Testing Encore Go Applications
## Instructions
Encore Go uses standard Go testing with `encore test`.
### Run Tests
```bash
# Run all tests with Encore (recommended)
encore test ./...
# Run tests for a specific package
encore test ./user/...
# Run with verbose output
encore test -v ./...
```
Using `encore test` instead of `go test` is recommended because it:
- Sets up test databases automatically
- Provides isolated infrastructure per test
- Handles service dependencies
### Test an API Endpoint
```go
// hello/hello_test.go
package hello
import (
"context"
"testing"
)
func TestHello(t *testing.T) {
ctx := context.Background()
resp, err := Hello(ctx)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if resp.Message != "Hello, World!" {
t.Errorf("expected 'Hello, World!', got '%s'", resp.Message)
}
}
```
### Test with Request Parameters
```go
// user/user_test.go
package user
import (
"context"
"testing"
)
func TestGetUser(t *testing.T) {
ctx := context.Background()
user, err := GetUser(ctx, &GetUserParams{ID: "123"})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if user.ID != "123" {
t.Errorf("expected ID '123', got '%s'", user.ID)
}
}
```
### Test Database Operations
Encore provides isolated test databases:
```go
// user/user_test.go
package user
import (
"context"
"testing"
"encore.dev/storage/sqldb"
)
func TestCreateUser(t *testing.T) {
ctx := context.Background()
// Clean up
_, _ = sqldb.Exec(ctx, db, "DELETE FROM users")
// Create user
created, err := CreateUser(ctx, &CreateUserParams{
Email: "[email protected]",
Name: "Test User",
})
if err != nil {
t.Fatalf("failed to create user: %v", err)
}
// Retrieve and verify
retrieved, err := GetUser(ctx, &GetUserParams{ID: created.ID})
if err != nil {
t.Fatalf("failed to get user: %v", err)
}
if retrieved.Email != "[email protected]" {
t.Errorf("expected email '[email protected]', got '%s'", retrieved.Email)
}
}
```
### Test Service-to-Service Calls
```go
// order/order_test.go
package order
import (
"context"
"testing"
)
func TestCreateOrder(t *testing.T) {
ctx := context.Background()
// Service calls work normally in tests
order, err := CreateOrder(ctx, &CreateOrderParams{
UserID: "user-123",
Items: []OrderItem{
{ProductID: "prod-1", Quantity: 2},
},
})
if err != nil {
t.Fatalf("failed to create order: %v", err)
}
if order.Status != "pending" {
t.Errorf("expected status 'pending', got '%s'", order.Status)
}
}
```
### Test Error Cases
```go
package user
import (
"context"
"errors"
"testing"
"encore.dev/beta/errs"
)
func TestGetUser_NotFound(t *testing.T) {
ctx := context.Background()
_, err := GetUser(ctx, &GetUserParams{ID: "nonexistent"})
if err == nil {
t.Fatal("expected error, got nil")
}
// Check error code
var e *errs.Error
if errors.As(err, &e) {
if e.Code != errs.NotFound {
t.Errorf("expected NotFound, got %v", e.Code)
}
} else {
t.Errorf("expected errs.Error, got %T", err)
}
}
```
### Test Pub/Sub
```go
// notifications/notifications_test.go
package notifications
import (
"context"
"testing"
"myapp/events"
)
func TestPublishOrderCreated(t *testing.T) {
ctx := context.Background()
msgID, err := events.OrderCreated.Publish(ctx, &events.OrderCreatedEvent{
OrderID: "order-123",
UserID: "user-456",
Total: 9999,
})
if err != nil {
t.Fatalf("failed to publish: %v", err)
}
if msgID == "" {
t.Error("expected message ID, got empty string")
}
}
```
### Test Cron Jobs
Test the underlying function, not the cron schedule:
```go
// cleanup/cleanup_test.go
package cleanup
import (
"context"
"testing"
)
func TestCleanupExpiredSessions(t *testing.T) {
ctx := context.Background()
// Create some expired sessions first
createExpiredSession(ctx)
// Call the endpoint directly
err := CleanupExpiredSessions(ctx)
if err != nil {
t.Fatalf("cleanup failed: %v", err)
}
// Verify cleanup happened
count := countSessions(ctx)
if count != 0 {
t.Errorf("expected 0 sessions, got %d", count)
}
}
```
### Table-Driven Tests
```go
func TestValidateEmail(t *testing.T) {
tests := []struct {
name string
email string
wantErr bool
}{
{"valid email", "[email protected]", false},
{"missing @", "userexample.com", true},
{"empty", "", true},
{"valid with subdomain", "[email protected]", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := validateEmail(tt.email)
if (err != nil) != tt.wantErr {
t.Errorf("validateEmail(%q) error = %v, wantErr %v", tt.email, err, tt.wantErr)
}
})
}
}
```
### Test with Subtests
```go
func TestUserCRUD(t *testing.T) {
ctx := context.Background()
var userID string
t.Run("create", func(t *testing.T) {
user, err := CreateUser(ctx, &CreateUserParams{
Email: "[email protected]",
Name: "Test",
})
if err != nil {
t.Fatalf("create failed: %v", err)
}
userID = user.ID
})
t.Run("read", func(t *testing.T) {
user, err := GetUser(ctx, &GetUserParams{ID: userID})
if err != nil {
t.Fatalf("read failed: %v", err)
}
if user.Email != "[email protected]" {
t.Errorf("wrong email: %s", user.Email)
}
})
t.Run("delete", func(t *testing.T) {
err := DeleteUser(ctx, &DeleteUserParams{ID: userID})
if err != nil {
t.Fatalf("delete failed: %v", err)
}
})
}
```
### Test Database Isolation
Create isolated, fully-migrated test databases using `et.NewTestDatabase()`:
```go
import "encore.dev/et"
func TestWithFreshDatabase(t *testing.T) {
// Creates a new database with all migrations applied
testDB := et.NewTestDatabase(t, db)
// Use testDB for queries - it's completely isolated
_, err := testDB.Exec(ctx, "INSERT INTO users (email) VALUES ($1)", "[email protected]")
if err != nil {
t.Fatal(err)
}
}
```
### Service Instance Isolation
By default, service structs are shared across tests for performance. Enable isolation when tests modify service state:
```go
import "encore.dev/et"
func TestWithServiceIsolation(t *testing.T) {
// Enable service instance isolation for this test
et.EnableServiceInstanceIsolation()
// Now this test gets its own service struct instance
// preventing state interference with other tests
}
```
### Test Tracing Dashboard
View test execution traces in the development dashboard at `http://localhost:9400` while tests run. This helps diagnose failures by showing:
- Request/response data
- Database queries
- Service-to-service calls
- Errors and stack traces
### Mocking Endpoints and Services
Mock endpoints or entire services for isolated unit testing:
```go
import "encore.dev/et"
func TestWithMockedEndpoint(t *testing.T) {
// Mock a specific endpoint
et.MockEndpoint(products.GetPrice, func(ctx context.Context, p *products.PriceParams) (*products.PriceResponse, error) {
return &products.PriceResponse{Price: 100}, nil
})
// Mock an entire service
et.MockService("products", &mockProductService{})
}
```
### Guidelines
- Use `encore test` to run tests with infrastructure setup
- Each test gets access to real infrastructure (databases, Pub/Sub)
- Test API endpoints by calling them directly as functions
- Service-to-service calls work normally in tests
- Use table-driven tests for testing multiple cases
- Use `et.NewTestDatabase()` for isolated database testing
- Use `et.EnableServiceInstanceIsolation()` when tests modify service state
- Don't mock Encore infrastructure - use the real thing
- Mock external dependencies (third-party APIs, email services, etc.)
© encoredev · Apache-2.0 · encoredev/skills