测试随机函数应验证整体分布与逻辑约束而非单次结果:用统计分析(频次、极值、均值)、卡方检验、可注入随机源、边界/不变量检查及分场景验证(游戏重范围、统计重分布、安全重类型异常)。

测试含随机数的函数,核心不是验证“某一次输出是否固定”,而是验证“整体行为是否符合预期分布和逻辑约束”。直接断言具体数值会失败,必须换思路。
用统计规律代替单次断言
对大量重复调用做频次分析,确认结果落在合理区间内:
- 生成10000个
[1,6]整数,各数字出现次数应在1500–1800之间(±15%属正常波动) - 生成10000个
[0,1)浮点数,检查Math.min()是否接近0、Math.max()是否接近1,且均值≈0.5 - 用
chi-squared test(卡方检验)量化分布均匀性——可借助simple-statistics等轻量库
分离随机源,便于可控注入
把随机数生成逻辑抽离为参数,测试时传入确定性序列:
- 原函数:
function rollDice() { return Math.floor(Math.random() * 6) + 1; } - 重构后:
function rollDice(randomFn = Math.random) { return Math.floor(randomFn() * 6) + 1; } - 测试时传入预设数组:
const mockRng = (function*() { yield* [0.1, 0.9, 0.5]; })(); rollDice(() => mockRng.next().value); // 确定返回 1, 6, 4
验证边界与不变量
不关心具体值,只检查是否守住了规则:
- 洗牌函数
shuffle(arr):断言arr.length === shuffled.length且shuffled.every(x => arr.includes(x)) - 验证码生成
genCode(6):断言typeof result === 'string'、result.length === 6、/^[0-9]{6}$/.test(result) - 安全令牌
genToken(32):断言长度准确、字符集合规、无undefined或null
区分场景,明确测试目标
不同用途的随机函数,验证重点不同:
- 游戏/UI类:关注范围正确、无越界、无逻辑漏洞(如骰子不会出0)
- 模拟/统计类:强调大样本下分布特征(均值、方差、直方图形状)
-
安全类(如
crypto.getRandomValues):不测“随机性”,而测Uint8Array长度、类型、是否抛异常;真随机性交由专业工具(如Dieharder)验证
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











