gt

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 6, 2026 License: MIT Imports: 4 Imported by: 0

README

gt (Go Test)

Go Report Card GoDoc Coverage Status

gt is a minimalist, idiomatic testing library for Go. It provides powerful assertions and a lightweight spying mechanism without the bloat of heavy frameworks.

Designed for Effective Go:

  • Zero Dependencies: Pure Go standard library.
  • No Magic: Explicit, readable, and type-safe.
  • Extensible: Plug in your favorite diff tools (like go-cmp) or JSON comparators.

Installation

go get github.com/axpira/gt

Quick Start

gt works alongside the standard testing package.

package main_test

import (
	"errors"
	"testing"

	"github.com/axpira/gt"
)

func TestExample(t *testing.T) {
	got := 2 + 2
	gt.Equal(t, "math check", 4, got)

	err := errors.New("something went wrong")
	target := errors.New("something went wrong")
	
	// Checks if err matches target (using errors.Is)
	gt.ErrorIs(t, "error check", err, target)
}

Advanced Usage

Custom Diff Function

By default, gt uses reflect.DeepEqual. You can easily plug in google/go-cmp for better diffs:

import "github.com/google/go-cmp/cmp"

// ... inside test
gt.Equal(t, "complex struct", want, got, gt.WithDiffFunc(func(want, got any) string {
    if diff := cmp.Diff(want, got); diff != "" {
        return diff
    }
    return ""
}))
JSON Comparison

Compare JSON strings or bytes ignoring whitespace:

gt.Equal(t, "json check", 
    []byte(`{"id": 1, "name": "foo"}`), 
    []byte(`{
        "name": "foo",
        "id": 1
    }`), 
    gt.WithJSONDiff,
)
Custom Failure Behavior

Change how gt handles failures (default is FailNow):

// Don't stop execution on failure
gt.Equal(t, "soft check", 1, 2, gt.WithFailLazy())

// Custom hook (e.g., for logging)
gt.Equal(t, "hook check", 1, 2, gt.WithFailHook(func() {
    t.Log("Assertion failed!")
}))

Mocking & Spying

gt includes a spy package to facilitate Manual Mocking. Instead of generating complex mock code, we encourage defining simple mock structs that record their interactions.

The spy.Recorder

The spy.Recorder is a thread-safe helper that records function calls and arguments.

Step-by-Step Example

1. Define the Interface

type Repository interface {
    Save(ctx context.Context, data string) error
}

2. Create the Mock Embed spy.Recorder in your struct.

import "github.com/axpira/gt/spy"

type MockRepo struct {
    spy.Recorder
    
    // Configurable return values
    SaveErr error
}

func (m *MockRepo) Save(ctx context.Context, data string) error {
    // Record the call. 
    // It automatically captures the method name "Save" and arguments.
    m.Record(ctx, data) 
    return m.SaveErr
}

3. Use in Test

func TestService_Save(t *testing.T) {
    // Setup Mock
    mock := &MockRepo{SaveErr: nil}
    
    // Execute logic
    err := mock.Save(context.Background(), "important data")
    
    // Assertions
    gt.ErrorIs(t, "save error", err, nil)
    
    // Verify Interactions
    // History is [][]any: [[MethodName, Arg1, Arg2...], [MethodName, ...]]
    
    gt.Equal(t, "call count", 1, len(mock.History))
    
    lastCall := mock.History[0]
    gt.Equal(t, "method name", "Save", lastCall[0])
    gt.Equal(t, "argument", "important data", lastCall[2]) // [0]=Name, [1]=ctx, [2]=data
}
Why Manual Mocks?
  • Type Safety: Compiler checks your mocks.
  • Refactoring: Rename methods and your mocks update automatically (mostly).
  • Simplicity: No code generation steps or complex DSLs.

License

MIT License. See LICENSE file for details.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	DefaultDiffFunc diffFunc = func(want, got any) string {
		if !reflect.DeepEqual(want, got) {
			return fmt.Sprintf("want: %#+v\ngot:  %#+v", want, got)
		}
		return ""
	}
	DefaultFailFunc = func(t testingT) {
		t.FailNow()
	}
	DefaultFailHookFunc = func() {}
)

Functions

func Equal

func Equal(t testingT, prefix string, want, got any, opts ...option) bool

func ErrorIs

func ErrorIs(t testingT, prefix string, err, target error, opts ...option) bool

func NotEqual

func NotEqual(t testingT, prefix string, want, got any, opts ...option) bool

func With

func With(opts ...option) config

func WithDiffFunc

func WithDiffFunc(diffFn diffFunc) option

func WithFailHook

func WithFailHook(fn func()) option

func WithFailLazy

func WithFailLazy() option

func WithJSONDiff

func WithJSONDiff(cfg *config)

func WithMarshal

func WithMarshal(marshal func(input any) (any, error)) option

Types

This section is empty.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL