Testing Introduction

Nimbus embraces Go's built-in testing package and adds a testing.TestClient for convenient HTTP testing. No extra test runner needed — just go test.

Test file conventions

Go discovers tests automatically. Place test files alongside the code they test, using the _test.go suffix.

  • app/controllers/users_test.go — tests for the users controller
  • app/models/user_test.go — tests for the user model
  • main_test.go — integration and HTTP tests

Setting up a test app

Create a helper that builds a Nimbus app configured for testing. Use an in-memory SQLite database to keep tests fast and isolated.

package main

import (
    "github.com/CodeSyncr/nimbus"
    "github.com/CodeSyncr/nimbus/database"
    "github.com/CodeSyncr/nimbus/middleware"
)

func setupTestApp() *nimbus.App {
    app := nimbus.New()
    app.Router.Use(middleware.Recover())

    db, _ := database.Connect("sqlite", ":memory:")
    app.Container.Singleton("db", func() *gorm.DB {
        return db
    })

    // Register routes
    app.Router.Get("/health", healthHandler)
    app.Router.Get("/users", listUsersHandler)
    app.Router.Post("/users", createUserHandler)

    return app
}

The TestClient

Nimbus provides testing.NewTestClient(router) which sends requests directly to the router without starting a real HTTP server. It returns *httptest.ResponseRecorder.

import nimbustest "github.com/CodeSyncr/nimbus/testing"

func TestHealthEndpoint(t *testing.T) {
    app := setupTestApp()
    client := nimbustest.NewTestClient(app.Router)

    resp := client.Get("/health")

    if resp.Code != 200 {
        t.Errorf("expected 200, got %d", resp.Code)
    }
}

Test database

For database tests, use :memory: with SQLite. Run migrations inside the test setup to get a clean schema each time.

func setupTestDB() *gorm.DB {
    db, _ := database.Connect("sqlite", ":memory:")
    db.AutoMigrate(&User{}, &Post{})
    return db
}

Writing a basic test

Test functions must start with Test and accept *testing.T.

func TestCreateUser(t *testing.T) {
    app := setupTestApp()
    client := nimbustest.NewTestClient(app.Router)

    body := []byte(`{"name":"Alice","email":"alice@example.com"}`)
    resp := client.Post("/users", body)

    if resp.Code != 201 {
        t.Fatalf("expected 201, got %d", resp.Code)
    }
}

Running tests

Use the standard Go test commands:

# Run all tests
go test ./...

# Run tests in a specific package
go test ./app/controllers/...

# Run with verbose output
go test -v ./...

# Run a specific test function
go test -run TestCreateUser ./...

Tips

  • Use t.Parallel() at the top of tests that can run concurrently.
  • Use table-driven tests for handler endpoints that need multiple input/output cases.
  • Keep test setup DRY with helper functions like setupTestApp().
  • Use t.Cleanup() to tear down resources when a test finishes.