The standard testing assertion style for AI Driven Development (AIDD) and software agents.
A Go port of the paralleldrive/riteway testing philosophy.
Riteway is a testing assertion style and philosophy which leads to simple, readable, helpful unit tests for humans and AI agents.
It lets you write better, more readable tests with a fraction of the code that traditional assertion frameworks would use.
Riteway is the AI-native way to build a modern test suite. It pairs well with Go's testing package, Claude Code, Cursor Agent, and more.
- Readable
- Isolated/Integrated
- Thorough
- Explicit
Riteway forces you to write Readable, Isolated, and Explicit tests, because that's the only way you can use the API. It also makes it easier to be thorough by making test assertions so simple that you'll want to write more of them.
Riteway's structured approach makes it ideal for AIDD:
📖 Learn more: Better AI Driven Development with Test Driven Development
- Clear requirements: The given/should structure and 5-question framework help AI better understand exactly what to build
- Readable by design: Natural language descriptions make tests comprehensible to both humans and AI
- Simple API: Minimal surface area reduces AI confusion and hallucinations
- Token efficient: Concise syntax saves valuable context window space
There are 5 questions every unit test must answer. Riteway forces you to answer them.
- What is the unit under test (module, function, class, whatever)?
- What should it do? (Prose description)
- What was the actual output?
- What was the expected output?
- How do you reproduce the failure?
Enforcing these questions produces failure messages that are immediately actionable — no guessing, no archaeology.
go get github.com/mycargus/riteway-golangThe module path is github.com/mycargus/riteway-golang but the Go package name is riteway:
import riteway "github.com/mycargus/riteway-golang"
// then use as: riteway.Assert(...)type Case[T any] struct {
Given string // describes the input or precondition
Should string // describes the expected behavior
Actual T // the computed value
Expected T // the value we expect
}func Assert[T any](t testing.TB, c Case[T], opts ...cmp.Option)Compares Actual and Expected using go-cmp deep equality. On mismatch, reports a failure with a structured message and human-readable diff. Non-fatal: calls t.Errorf, so the test continues after a failed assertion.
- Validates that
GivenandShouldare non-empty and non-whitespace. - Accepts optional
cmp.Optionvalues for custom comparison (e.g.,cmpopts.IgnoreUnexportedto skip unexported fields,cmp.AllowUnexportedto compare them). - Works with
*testing.T,*testing.B, and*testing.F.
func Require[T any](t testing.TB, c Case[T], opts ...cmp.Option)Identical to Assert but fatal: calls t.Fatalf, so the test stops immediately on the first failed assertion. Use Require when subsequent assertions are only meaningful if the current one passes.
func Try[T any](fn func() T) (result T, err error)Calls fn and recovers from any panic, returning it as an error. Useful for asserting panic behavior in tests. Does not catch runtime.Goexit (i.e., t.FailNow/t.Fatal inside Try still terminate the subtest normally). On panic, result is the zero value of T. fn must not be nil.
func Match(text, substring string) string // case-sensitiveReturns substring if found in text, otherwise "". An empty substring always returns "" to avoid the ambiguous case where Match("anything", "") returns "" and is indistinguishable from "not found".
func MatchRegexp(text, pattern string) string // case-sensitive; use (?i) for case-insensitiveReturns the first match of pattern in text, or "" if not found. By default . does not match newlines; use (?s) to enable dotall mode. Panics if:
patternis not a valid regular expression, orpatterncan match an empty string (e.g.,x*,.*) — because the result would be indistinguishable from "not found". Use patterns that require at least one character (e.g.,x+).
Use Try to test for either panic. For regexp syntax including inline flags ((?i) for case-insensitive, (?s) for dotall), see regexp/syntax.
func TestAdd(t *testing.T) {
riteway.Assert(t, riteway.Case[int]{
Given: "no arguments",
Should: "return 0",
Actual: Add(),
Expected: 0,
})
}result, err := db.Query(ctx, q)
riteway.Require(t, riteway.Case[bool]{
Given: "a valid query",
Should: "not return an error",
Actual: err == nil,
Expected: true,
})
// only reached if the Require above passed
riteway.Assert(t, riteway.Case[int]{
Given: "a valid query",
Should: "return one row",
Actual: len(result),
Expected: 1,
})func TestSquare(t *testing.T) {
cases := []riteway.Case[int]{
{Given: "zero", Should: "return 0", Actual: Square(0), Expected: 0},
{Given: "positive", Should: "return 4", Actual: Square(2), Expected: 4},
{Given: "negative", Should: "return 9", Actual: Square(-3), Expected: 9},
}
for _, c := range cases {
t.Run("Given "+c.Given, func(t *testing.T) {
riteway.Assert(t, c)
})
}
}import "github.com/google/go-cmp/cmp/cmpopts"
riteway.Assert(t, riteway.Case[Config]{
Given: "default settings",
Should: "use port 8080",
Actual: NewConfig(),
Expected: Config{Port: 8080},
}, cmpopts.IgnoreUnexported(Config{}))_, err := riteway.Try(func() int { panic("boom") })
riteway.Assert(t, riteway.Case[string]{
Given: "a panicking function",
Should: "return the panic message as an error",
Actual: err.Error(),
Expected: "boom",
})riteway.Assert(t, riteway.Case[string]{
Given: "rendered HTML with a title",
Should: "contain the page title",
Actual: riteway.Match(html, "Welcome"),
Expected: "Welcome",
})_, err := riteway.Try(func() string {
return riteway.MatchRegexp("text", "[invalid")
})
riteway.Assert(t, riteway.Case[bool]{
Given: "an invalid regexp pattern",
Should: "panic",
Actual: err != nil,
Expected: true,
})When a test fails, riteway produces:
--- FAIL: TestSquare/Given_negative (0.00s)
riteway_test.go:42: Given negative: should return 9 (-want +got):
int(
- 9,
+ 10,
)
- Go 1.21+
This library is a Go port of paralleldrive/riteway, originally created by Eric Elliott. The five-question testing philosophy, API design, and naming conventions are derived from that work.
MIT