GitHub - cweill/gotests: Automatically generate Go test boilerplate from your source code. (original) (raw)

gotests is a powerful Go test generator that automatically creates table-driven tests from your source code. It analyzes function and method signatures to generate comprehensive test scaffolding, saving you time and ensuring consistency across your test suite.

Key Features

Demo

The following shows gotests in action using the official Sublime Text 3 plugin. Plugins also exist for Emacs, also Emacs, Vim, Atom Editor, Visual Studio Code, and IntelliJ Goland.

demo

Installation

Minimum Go version: Go 1.22

Use go install to install and update:

$ go install github.com/cweill/gotests/gotests@latest

Usage

From the commandline, gotests can generate Go tests for specific source files or an entire directory. By default, it prints its output to stdout.

$ gotests [options] PATH ...

Available options:

  -all                  generate tests for all functions and methods

  -excl                 regexp. generate tests for functions and methods that don't
                         match. Takes precedence over -only, -exported, and -all

  -exported             generate tests for exported functions and methods. Takes
                         precedence over -only and -all

  -i                    print test inputs in error messages

  -named                switch table tests from using slice to map (with test name for the key)

  -only                 regexp. generate tests for functions and methods that match only.
                         Takes precedence over -all

  -nosubtests           disable subtest generation when >= Go 1.7

  -parallel             enable parallel subtest generation when >= Go 1.7.

  -w                    write output to (test) files instead of stdout

  -template_dir         Path to a directory containing custom test code templates. Takes
                         precedence over -template. This can also be set via environment
                         variable GOTESTS_TEMPLATE_DIR

  -template             Specify custom test code templates, e.g. testify. This can also
                         be set via environment variable GOTESTS_TEMPLATE

  -template_params_file read external parameters to template by json with file

  -template_params      read external parameters to template by json with stdin

  -use_go_cmp           use cmp.Equal (google/go-cmp) instead of reflect.DeepEqual

  -ai                   generate test cases using AI (requires Ollama)

  -ai-model             AI model to use (default "qwen2.5-coder:0.5b")

  -ai-endpoint          Ollama API endpoint (default "http://localhost:11434")

  -ai-min-cases         minimum number of test cases to generate with AI (default 3)

  -ai-max-cases         maximum number of test cases to generate with AI (default 10)

  -version              print version information and exit

AI-Powered Test Generation

gotests can generate intelligent test cases using local LLMs via Ollama. This feature analyzes your function implementations and generates realistic test values, edge cases, and error conditions.

Quick Start

  1. Install Ollama (https://ollama.ai)
  2. Pull a model:
    ollama pull qwen2.5-coder:0.5b # Small, fast model (400MB)

or

ollama pull llama3.2:latest # Larger, more capable (2GB) 3. Generate tests with AI:
gotests -all -ai -w yourfile.go

Example

Given this function:

func CalculateDiscount(price float64, percentage int) (float64, error) { if price < 0 { return 0, errors.New("price cannot be negative") } if percentage < 0 || percentage > 100 { return 0, errors.New("percentage must be between 0 and 100") } discount := price * float64(percentage) / 100.0 return price - discount, nil }

The AI generates (showing 3 cases; by default, the AI generates between 3-10 cases):

func TestCalculateDiscount(t *testing.T) { type args struct { price float64 percentage int } tests := []struct { name string args args want float64 wantErr bool }{ { name: "valid discount", args: args{price: 100.0, percentage: 20}, want: 80.0, wantErr: false, }, { name: "negative price", args: args{price: -10.0, percentage: 20}, want: 0, wantErr: true, }, { name: "invalid percentage", args: args{price: 100.0, percentage: 150}, want: 0, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := CalculateDiscount(tt.args.price, tt.args.percentage) if (err != nil) != tt.wantErr { t.Errorf("CalculateDiscount() error = %v, wantErr %v", err, tt.wantErr) return } if got != tt.want { t.Errorf("CalculateDiscount() = %v, want %v", got, tt.want) } }) } }

AI Options

Use a different model

gotests -all -ai -ai-model llama3.2:latest -w yourfile.go

Generate a specific number of test cases (min = max)

gotests -all -ai -ai-min-cases 5 -ai-max-cases 5 -w yourfile.go

Generate a range of test cases (AI chooses between 3-7)

gotests -all -ai -ai-min-cases 3 -ai-max-cases 7 -w yourfile.go

Combine with other flags

gotests -exported -ai -parallel -w yourfile.go

How It Works

Supported Features

✅ Simple types (int, string, bool, float) ✅ Complex types (slices, maps, structs, pointers) ✅ Error returns and validation ✅ Variadic parameters ✅ Methods with receivers ✅ Multiple return values

Privacy & Security

What data is sent to the LLM:

Privacy considerations:

If using cloud providers in the future:

Quick Start Examples

Generate tests for a single function

Given a file math.go:

package math

func Add(a, b int) int { return a + b }

Generate a test:

$ gotests -only Add -w math.go

This creates math_test.go with:

func TestAdd(t *testing.T) { type args struct { a int b int } tests := []struct { name string args args want int }{ // TODO: Add test cases. } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := Add(tt.args.a, tt.args.b); got != tt.want { t.Errorf("Add() = %v, want %v", got, tt.want) } }) } }

Generate tests for all exported functions

$ gotests -all -exported -w .

This generates tests for all exported functions in the current directory.

Generate tests recursively

This generates tests for all functions in the current directory and all subdirectories.

Generate tests with testify

$ gotests -all -template testify -w calculator.go

This generates tests using the testify assertion library.

Common workflows

Generate tests for all exported functions in a package

$ gotests -exported -w pkg/*.go

Generate only tests for specific functions matching a pattern

$ gotests -only "^Process" -w handler.go

Generate tests excluding certain functions

$ gotests -all -excl "^helper" -w utils.go

Generate parallel subtests

$ gotests -all -parallel -w service.go

Go Generics Support

gotests fully supports Go generics (type parameters) introduced in Go 1.18+. It automatically generates tests for generic functions and methods on generic types.

Example: Generic Function

Given this generic function:

func FindFirst[T comparable](slice []T, target T) (int, error) { for i, v := range slice { if v == target { return i, nil } } return -1, ErrNotFound }

Running gotests -all -w yourfile.go generates:

func TestFindFirst(t *testing.T) { type args struct { slice []string target string } tests := []struct { name string args args want int wantErr bool }{ // TODO: Add test cases. } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := FindFirst[string](tt.args.slice, tt.args.target) if (err != nil) != tt.wantErr { t.Errorf("FindFirst() error = %v, wantErr %v", err, tt.wantErr) return } if got != tt.want { t.Errorf("FindFirst() = %v, want %v", got, tt.want) } }) } }

Example: Methods on Generic Types

gotests also supports methods on generic types:

type Set[T comparable] struct { m map[T]struct{} }

func (s *Set[T]) Add(v T) { if s.m == nil { s.m = make(map[T]struct{}) } s.m[v] = struct{}{} }

Generates:

func TestSet_Add(t *testing.T) { type args struct { v string } tests := []struct { name string s *Set[string] args args }{ // TODO: Add test cases. } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s := &Set[string]{} s.Add(tt.args.v) }) } }

Type Constraint Mapping

gotests uses intelligent defaults for type parameter instantiation:

This ensures generated tests use appropriate concrete types for testing generic code.

Contributions

Contributing guidelines are in CONTRIBUTING.md.

License

gotests is released under the Apache 2.0 License.