如何对随机几何函数进行单元测试?
几何随机点生成函数的黑盒单元测试方案
针对这类生成几何图形内随机点的函数,黑盒测试可以从边界合法性、分布均匀性、辅助功能验证三个核心维度展开,完全不依赖内部实现细节:
一、边界合法性测试(硬约束校验)
这是最基础的测试,确保所有生成的点严格落在目标图形的内部或边界上,只要有一个点不符合就判定失败。
针对不同图形的校验逻辑:
- 矩形:对生成的点
(px, py),验证x ≤ px < x+width且y ≤ py < y+height(因为random()返回[0,1),所以结果是左闭右开区间) - 圆形:计算点到圆心的距离
d = sqrt((px-centerX)² + (py-centerY)²),验证d ≤ radius - 线段:设线段两端点为
A(x1,y1)、B(x2,y2),验证:- 点
P在线段的包围盒内:min(x1,x2) ≤ px ≤ max(x1,x2)且min(y1,y2) ≤ py ≤ max(y1,y2) - 向量
AP与AB的点积≥0,且向量BP与BA的点积≥0(确保点在线段的参数范围内)
- 点
- 三角形:设三个顶点为
A、B、C,计算点P的重心坐标权重,验证三个权重均≥0且和为1;或者验证点在三条边的内侧(通过叉积判断方向) - 椭圆:代入椭圆方程
((px-h)/a)² + ((py-k)/b)² ≤ 1((h,k)为中心,a、b为半长/短轴)
测试步骤:
- 生成大量样本点(建议104~105个,平衡测试速度和覆盖度)
- 对每个点执行对应图形的边界校验逻辑
- 若存在任意一个点不满足约束,测试直接失败
二、分布均匀性测试(随机性核心验证)
黑盒下无法直接看内部随机数调用,只能通过统计方法验证点的分布是否符合「图形内均匀分布」的预期:
1. 直方图卡方检验
- 将目标图形划分为等面积的子区域(比如矩形分成10×10的网格,圆形分成5个环形+8个扇形的组合)
- 统计每个子区域内的点数量,计算实际频率
- 用卡方检验判断实际频率与理论均匀分布(每个子区域预期点数=总点数/子区域数)的差异是否在可接受范围内(卡方值小于临界值则通过)
2. 累积分布函数(CDF)校验
针对图形的一维特征验证分布:
- 矩形:提取所有点的
x坐标,其CDF应该是[x, x+width)上的线性函数。将x坐标排序后,计算累积比例,与理论CDF对比,用KS检验判断是否符合均匀分布 - 圆形:提取点到圆心的距离
r,由于均匀分布的圆形随机点满足r²服从[0, radius²)的均匀分布,验证r²的CDF是否为线性函数即可
3. 蒙特卡洛面积验证
利用随机点的均匀性估算图形面积,与理论值对比:
- 用一个已知面积的简单图形(比如矩形)完全包围目标图形
- 生成大量点,统计落在目标图形内的比例,乘以包围图形的面积得到估算面积
- 验证估算面积与理论面积的误差在置信区间内(比如95%置信度下误差≤1%)
三、辅助功能测试
- 输出对象复用验证:传入自定义的
Vector2实例作为out参数,验证函数返回的是同一个实例,且其x/y属性被正确修改 - 边界参数测试:传入极端参数(比如
width=0、radius=0),验证函数返回合法点(比如矩形返回(x,y),圆形返回圆心) - 可选:确定性Mock测试:如果测试框架允许mock
random()函数的返回值,可以验证特定输入下的输出(比如random()返回0时,矩形返回(x,y),圆形返回圆心)
示例测试代码片段(以矩形函数为例)
// 边界合法性测试 test('randomPointInRectangle returns points within bounds', () => { const x = 10, y = 20, width = 30, height = 40; const sampleCount = 10000; for (let i = 0; i < sampleCount; i++) { const point = randomPointInRectangle(x, y, width, height); expect(point.x).toBeGreaterThanOrEqual(x); expect(point.x).toBeLessThan(x + width); expect(point.y).toBeGreaterThanOrEqual(y); expect(point.y).toBeLessThan(y + height); } }); // 分布均匀性测试(x坐标均匀性) test('randomPointInRectangle x-coordinate is uniformly distributed', () => { const x = 0, y = 0, width = 100, height = 100; const sampleCount = 10000; const bins = 10; const binSize = width / bins; const counts = new Array(bins).fill(0); for (let i = 0; i < sampleCount; i++) { const point = randomPointInRectangle(x, y, width, height); const binIndex = Math.floor(point.x / binSize); counts[binIndex]++; } // 卡方检验简化版:预期每个bin有1000个点,允许±10%误差 const expected = sampleCount / bins; counts.forEach(count => { expect(count).toBeGreaterThanOrEqual(expected * 0.9); expect(count).toBeLessThanOrEqual(expected * 1.1); }); });
内容的提问来源于stack exchange,提问作者HankMoody
相关产品推荐
相关产品推荐

