Testing
Go testing package vs Jest/Vitest — table-driven vs describe/it
Introduction
In this lesson, you'll learn about testing in TypeScript. Coming from Go, you already have a foundation for understanding this concept. We'll build on that knowledge while highlighting the key differences.
In Go, you're familiar with go testing package vs jest/vitest — table-driven vs describe/it.
TypeScript has its own approach to go testing package vs jest/vitest — table-driven vs describe/it, which we'll explore step by step.
The TypeScript Way
Let's see how TypeScript handles this concept. Here's a typical example:
// math.test.ts
import { describe, it, expect, test } from "vitest";
import { add, divide } from "./math";
describe("math", () => {
it("adds two numbers", () => {
expect(add(1, 2)).toBe(3);
});
// Table-driven via test.each
test.each([
[6, 3, 2],
// [1, 0, throws]
])("divide(%i,%i)=%i", (a, b, expected) => {
expect(divide(a, b)).toBe(expected);
});
it("throws on divide by zero", () => {
expect(() => divide(1, 0)).toThrow("division by zero");
});
});
// npx vitest | watch mode
// npx vitest run | single run
// npx vitest --coverageComparing to Go
Here's how you might have written similar code in Go:
// math_test.go
package math
import (
"fmt"
"testing"
)
func TestAdd(t *testing.T) {
if got := Add(1, 2); got != 3 {
t.Errorf("Add(1,2)=%d; want 3", got)
}
}
// Table-driven tests
func TestDivide(t *testing.T) {
tests := []struct {
a, b float64
want float64
wantErr bool
}{
{6, 3, 2, false},
{1, 0, 0, true},
}
for _, tc := range tests {
t.Run(fmt.Sprintf("%v/%v", tc.a, tc.b), func(t *testing.T) {
got, err := Divide(tc.a, tc.b)
if tc.wantErr {
if err == nil { t.Error("expected error") }
return
}
if err != nil { t.Fatalf("unexpected: %v", err) }
if got != tc.want { t.Errorf("got %v; want %v", got, tc.want) }
})
}
}
func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ { Add(1, 2) }
}
// go test ./... | go test -v -run TestAdd | go test -bench=.You may be used to different syntax or behavior.
Go: _test.go files, TestXxx(t *testing.T), no framework needed
You may be used to different syntax or behavior.
TypeScript: .test.ts files, describe/it blocks, Vitest/Jest framework
You may be used to different syntax or behavior.
Table-driven (Go) vs test.each (Vitest) for parametrized tests
You may be used to different syntax or behavior.
Go error test: check err != nil; TypeScript: expect().toThrow()
You may be used to different syntax or behavior.
Go benchmarks built-in; TypeScript needs separate benchmark library
Step-by-Step Breakdown
1. Test Structure
Go functions are TestXxx(t *testing.T) in _test.go files — no framework. TypeScript uses describe/it blocks with a framework.
describe("add", () => {
it("returns sum", () => {
expect(add(1,2)).toBe(3);
});
});func TestAdd(t *testing.T) {
if got := Add(1,2); got != 3 {
t.Errorf("got %d; want 3", got)
}
}2. Parametrized Tests
Go uses table-driven tests (struct slice + t.Run). TypeScript uses test.each. Both create sub-tests for each case.
test.each([[1,2,3],[4,5,9]])("adds", ([a,b,c]) =>
expect(add(a,b)).toBe(c));tests:=[]struct{a,b,want int}{{1,2,3},{4,5,9}}
for _,tc:=range tests {
t.Run(fmt.Sprintf("%d+%d",tc.a,tc.b),func(t *testing.T){
if Add(tc.a,tc.b)!=tc.want{t.Fail()}
})
}3. Testing Errors
Go returns errors as values — check err != nil. TypeScript throws exceptions — use expect().toThrow().
expect(() => divide(1, 0)).toThrow("division by zero");_, err := Divide(1, 0)
if err == nil {
t.Error("expected error for divide by zero")
}4. Benchmarks
Go benchmarks are BenchmarkXxx(b *testing.B) — built in. TypeScript needs benchmark.js or vitest-bench for equivalent functionality.
// vitest-bench or benchmark.js
bench("add", () => { add(1, 2); });func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ { Add(1, 2) }
}
// go test -bench=BenchmarkAdd -benchmemCommon Mistakes
When coming from Go, developers often make these mistakes:
- Go: _test.go files, TestXxx(t *testing.T), no framework needed
- TypeScript: .test.ts files, describe/it blocks, Vitest/Jest framework
- Table-driven (Go) vs test.each (Vitest) for parametrized tests
Key Takeaways
- Go: _test.go + TestXxx(t *testing.T) — no framework; TypeScript: .test.ts + describe/it
- Table-driven (Go) vs test.each (TypeScript) for parametrized tests
- Go tests errors with err != nil; TypeScript uses expect().toThrow()
- Go benchmarks are built-in; TypeScript needs external benchmark libraries