A lightweight, dependency-minimal testing library for Go that provides detailed assertion messages through source code analysis. Designed to make your tests as clear, readable, and maintainable as the code being tested.
- Simplicity: Write standard Go expressions in your tests without learning a complex API
- Clarity: Get error messages that directly relate to your test code through source analysis
- Minimalism: Enjoy a small, focused API instead of numerous specialized assertions
- Readability: Keep your test code looking like regular Go code
- Composability: Easily create custom test checks
go get github.com/krostar/testThe library exposes two main functions:
Assert(t, condition, [msg...]): Reports test failure if condition is false but continues executionRequire(t, condition, [msg...]): Reports test failure and stops execution immediately if condition is false
package foo
import (
"context"
"errors"
"testing"
"github.com/krostar/test"
)
func Test_Something(t *testing.T) {
got := 42
want := 24
test.Assert(t, got == want)
err := errors.New("test error")
test.Assert(t, errors.Is(err, context.Canceled), "context should have canceled and produced an error")
}Output:
go test -v ./...
=== RUN Test_Something
test_test.go:13: Error: got is not equal to want
test_test.go:17: Error: context.Canceled is not in the error tree of err [context should have canceled and produced an error]
--- FAIL: Test_Something (0.36s)
FAILThe library generates detailed error messages by analyzing your test expressions:
// With simple expressions
test.Assert(t, user.Name == "John")
// Error: user.Name is not equal to "John"
// With compound expressions
test.Assert(t, err == nil && user != nil)
// Error: err is not nil, or user is nil
// With function calls
test.Assert(t, strings.Contains(response, "success"))
// Error: response does not contain "success"The check package provides several built-in checks for common testing scenarios:
import (
"testing"
"time"
"context"
"github.com/krostar/test"
"github.com/krostar/test/check"
)
func TestChecks(t *testing.T) {
// Deep comparison
got := map[string]int{"a": 1, "b": 2}
want := map[string]int{"b": 2, "a": 1}
test.Assert(check.Compare(t, got, want))
// Wait for async condition
test.Assert(check.Eventually(test.Context(t), t, func(ctx context.Context) error {
// Check some condition that may take time to become true
return nil
}, time.Millisecond*100))
// Verify a function panics
test.Assert(check.Panics(t, func() { panic("boom") }, nil))
// Invert a check
test.Assert(check.Not(check.Panics(t, func() { panic("boom") }, nil)))
// Verify zero values
test.Assert(check.ZeroValue(t, 0))
}You can easily create custom checks to extend functionality:
func IsValidUser(t test.TestingT, user *User) (test.TestingT, bool, string) {
if user == nil {
return t, false, "user is nil"
}
if user.ID == 0 {
return t, false, "user ID should not be zero"
}
if user.Name == "" {
return t, false, "user name should not be empty"
}
return t, true, "user is valid"
}
// Usage
test.Assert(IsValidUser(t, user))The double package provides test doubles for testing code that uses a testing.T interface:
import (
"testing"
"github.com/krostar/test"
"github.com/krostar/test/double"
)
func TestWithSpy(t *testing.T) {
// Create a spy on a fake to record calls
spyT := double.NewSpy(double.NewFake())
// Use the spy in your test
functionUnderTest(spyT)
// Verify calls were made
spyT.ExpectRecords(t, false,
double.SpyTestingTRecord{Method: "Logf", Inputs: []any{"Success: %s", double.SpyTestingTRecordIgnoreParam}},
)
// Verify test passed/failed
spyT.ExpectTestToPass(t)
}| Library | API Design | Implementation | Error Messages | Maintenance |
|---|---|---|---|---|
| Go Standard Library | ✅ Core functionality only | ✅ Standard go, no external dependencies | ❌ Basic messages requiring manual formatting | ✅ Part of go core |
| stretchr/testify | ❌ Heavy use of reflection |
✅ Detailed error messages ✅ Good diffs for complex types |
✅ Actively maintained ✅ Well-established in community |
|
| gotest.tools/v3 | ✅ Minimalist and clear | ✅ Thin layer over go testing lib | ✅ Detailed error messages ✅ Good diffs for complex types |
✅ Actively maintained |
| matryer/is | ✅ Thin layer over go testing lib | ❌ No longer actively maintained | ||
| krostar/test | ✅ Minimalist and clear | ✅ Thin layer over go testing lib | ✅ Detailed error messages |
✅ Actively maintained |