单元测试指南

好测试的 FIRST 原则

原则含义
Fast(快速)毫秒级执行;无 sleep、无 I/O
Independent(独立)测试间无共享状态;执行顺序无关
Repeatable(可重复)每次结果相同;无随机性、无时间依赖
Self-validating(自验证)自动判断通过/失败,无需人工检查
Timely(及时)与生产代码同步编写(TDD)或立即跟进

测试结构:AAA 模式

// JavaScript(Vitest / Jest)——AAA 模式 import { describe, it, expect, beforeEach } from 'vitest'; import { ShoppingCart } from './cart'; describe('ShoppingCart', () => { let cart; beforeEach(() => { cart = new ShoppingCart(); // 每个测试重置状态 }); it('无商品时总价为 0', () => { // Arrange(在 beforeEach 中完成) // Act const total = cart.total(); // Assert expect(total).toBe(0); }); it('多商品含折扣时正确计算总价', () => { // Arrange cart.add({ id: 1, price: 100, qty: 2 }); cart.add({ id: 2, price: 50, qty: 1 }); cart.applyDiscount(10); // 9折 // Act const total = cart.total(); // Assert expect(total).toBe(225); // (200 + 50) * 0.9 }); it('添加负价格商品时抛出异常', () => { expect(() => cart.add({ id: 1, price: -5, qty: 1 })) .toThrow('Price must be non-negative'); }); });

Go 单元测试

// Go——表驱动测试(惯用写法) func TestAdd(t *testing.T) { tests := []struct { name string a, b int want int }{ {"正整数", 2, 3, 5}, {"负正混合", -2, 5, 3}, {"均为负数", -3, -4, -7}, {"零值", 0, 0, 0}, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { got := calculator.Add(tc.a, tc.b) if got != tc.want { t.Errorf("Add(%d, %d) = %d, want %d", tc.a, tc.b, got, tc.want) } }) } } // 使用 testify 简化断言 func TestDivide(t *testing.T) { result, err := calculator.Divide(10, 2) require.NoError(t, err) assert.Equal(t, 5.0, result) _, err = calculator.Divide(10, 0) assert.ErrorIs(t, err, calculator.ErrDivisionByZero) }