Skip to content

Testing

MeGaNeKo edited this page Mar 20, 2026 · 1 revision

Testing

Creating a Test API

neomatest.New creates an in-memory API using the built-in flow adapter. No HTTP server is started.

import (
    "github.com/MeGaNeKoS/neoma/neomatest"
    "github.com/MeGaNeKoS/neoma/neoma"
)

_, api := neomatest.New(t)

Pass a custom config if needed:

config := neoma.DefaultConfig("Test API", "1.0.0")
config.RejectUnknownQueryParameters = true
_, api := neomatest.New(t, config)

neomatest.Wrap wraps an existing core.API for testing:

api := neomatest.Wrap(t, existingAPI)

TestAPI Interface

TestAPI embeds core.API and adds two methods:

type TestAPI interface {
    core.API
    Do(method, path string, args ...any) *httptest.ResponseRecorder
    DoCtx(ctx context.Context, method, path string, args ...any) *httptest.ResponseRecorder
}

Do and DoCtx are the only request methods. DoCtx accepts a context.Context as the first argument; Do uses context.Background().

Args

Variable args accept three types in any order:

  • string in "Header-Name: value" format sets a request header.
  • io.Reader is used as the raw request body.
  • struct, map, or slice is JSON-encoded and sent with Content-Type: application/json.

Complete Test Example

package myapi_test

import (
    "context"
    "encoding/json"
    "testing"

    "github.com/MeGaNeKoS/neoma/core"
    "github.com/MeGaNeKoS/neoma/neoma"
    "github.com/MeGaNeKoS/neoma/neomatest"
    "github.com/stretchr/testify/assert"
)

type CreateInput struct {
    Body struct {
        Name string `json:"name" minLength:"1"`
    }
}

type CreateOutput struct {
    Body struct {
        ID   int    `json:"id"`
        Name string `json:"name"`
    }
}

func createHandler(ctx context.Context, input *CreateInput) (*CreateOutput, error) {
    resp := &CreateOutput{}
    resp.Body.ID = 1
    resp.Body.Name = input.Body.Name
    return resp, nil
}

func TestCreate(t *testing.T) {
    _, api := neomatest.New(t)
    neoma.Post(api, "/items", createHandler)

    // Success
    resp := api.Do("POST", "/items", map[string]any{"name": "Widget"})
    assert.Equal(t, 200, resp.Code)

    var body struct {
        ID   int    `json:"id"`
        Name string `json:"name"`
    }
    json.Unmarshal(resp.Body.Bytes(), &body)
    assert.Equal(t, "Widget", body.Name)

    // Validation error
    resp = api.Do("POST", "/items", map[string]any{"name": ""})
    assert.Equal(t, 422, resp.Code)

    // With custom headers and context
    resp = api.DoCtx(context.Background(), "POST", "/items",
        "Authorization: Bearer token",
        map[string]any{"name": "Gadget"},
    )
    assert.Equal(t, 200, resp.Code)
}

Unit Testing with neomatest.NewContext

For testing handlers or middleware that need a core.Context directly:

import "github.com/MeGaNeKoS/neoma/neomatest"

op := &core.Operation{Method: "GET", Path: "/test"}
req := httptest.NewRequest("GET", "/test", nil)
w := httptest.NewRecorder()
ctx := neomatest.NewContext(op, req, w)

Clone this wiki locally