Introduction to specta#
specta is a Go testing library that emphasizes composition and reuse through matchers and test data factories.
Why specta?#
Traditional Go tests often suffer from:
- Duplicated assertions across test cases
- Brittle tests that break when adding new fields
- Verbose error messages that don’t clearly show what failed
- Inconsistent test data generation
specta solves these problems by providing:
- Composable matchers - Build complex assertions from simple pieces
- Partial matching - Assert only the fields that matter
- Clear error messages - Structured diffs with visual indicators
- Deterministic factories - Generate reproducible test data
Installation#
go get github.com/james-w/spectaQuick Start#
Here’s a simple example showing the power of matchers:
func TestUserValidation(t *testing.T) {
user := registerUser("alice@example.com", 30)
// Match individual values with built-in matchers
specta.AssertThat(t, user.Age, specta.GreaterThan(18))
specta.AssertThat(t, user.Email, specta.Contains("@example.com"))
// Combine matchers with AllOf
specta.AssertThat(t, user.Email, specta.AllOf(
specta.HasPrefix("alice"),
specta.HasSuffix(".com"),
specta.Contains("@"),
))
}When tests fail, you see clear error messages:
user.Age: expected value > 18 but got 15
user.Email: expected string to contain "@example.com" but got "alice@test.org"Core Concepts#
Matchers#
Matchers are reusable predicates that test values and provide detailed failure messages:
specta.AssertThat(t, value, specta.Equal(expected))
specta.AssertThat(t, age, specta.GreaterThanOrEqual(21))
specta.AssertThat(t, active, specta.IsTrue())
specta.AssertThat(t, name, specta.Not(specta.Equal("")))AssertThat vs RequireThat#
specta provides two assertion functions:
AssertThat - Reports failures but continues test execution:
specta.AssertThat(t, user.Name, specta.Equal("Alice"))
specta.AssertThat(t, user.Age, specta.GreaterThan(18))
// Both assertions run, even if first failsRequireThat - Stops test execution immediately on failure:
specta.RequireThat(t, userPtr, specta.IsNotNil[User]())
// Test stops here if userPtr is nil - prevents panic below
specta.AssertThat(t, userPtr.Name, specta.Equal("Alice"))When to use RequireThat:
- Guard conditions: When nil values would cause panics
- Prerequisites: When subsequent assertions depend on earlier conditions
- Fatal errors: When continuing after failure would produce misleading errors
When to use AssertThat:
- Independent checks: When failures don’t affect other assertions
- Multiple validations: When you want to see all failures at once
- Most cases: AssertThat is the default choice
Composition#
Build complex matchers from simple ones:
validEmail := specta.AllOf(
specta.Contains("@"),
specta.MatchesRegex(`^[a-z]+@[a-z]+\.[a-z]+$`),
)
specta.AssertThat(t, user.Email, validEmail)Available Built-in Matchers#
specta includes matchers for common scenarios:
- Equality:
Equal,DeepEqual,Is - Numeric:
GreaterThan,LessThan,GreaterThanOrEqual,LessThanOrEqual - Strings:
Contains,HasPrefix,HasSuffix,MatchesRegex - Boolean:
IsTrue,IsFalse - Composition:
AllOf,AnyOf,Not
See Core Matchers for the complete list including error matchers, time matchers, collection matchers, and more.
Partial Matching#
Only assert what matters for each test:
// Only care about the name and email, other fields can have any value
// This test won't break when new fields (like PhoneNumber, Address) are added
specta.AssertThat(t, user, MatchUser().
WithName(specta.Equal("Alice")).
WithEmail(specta.Contains("example.com")))Next Steps#
- Learn about Core Matchers - the building blocks
- Explore Code Generation for custom types
- Set up Test Data Factories for deterministic test data
Module Information#
- Module:
github.com/james-w/specta - Go Version: 1.22+
- License: MIT