第三章 测试数据生成:随机数据、边界值与特殊场景

数据生成这事儿,说简单也简单,说复杂能让你怀疑人生。

我刚开始做算法验证的时候,觉得随便写几个数跑一跑就行了。结果呢?被测试同学追着问「你这个边界测了吗?异常数据呢?」——嗯,从那以后,我再也不敢小看数据生成这一步了。

3.1 随机数据生成:让算法「见见世面」

随机数据,说白了就是给算法喂一堆「没见过」的输入。你想想看,如果每次测试都用同一组数据,算法早就背下来了,根本测不出真实能力。

我个人习惯,随机数据生成要满足三个条件:

  • 覆盖范围广:数值分布要均匀,别老集中在某个区间
  • 可复现:设置随机种子,出 bug 能回放
  • 数量可控:从几百到几百万,按需调整

来看一个简单的随机数据生成器(Python 示例):

import random
import string

def generate_random_data(size=1000, seed=42):
    random.seed(seed)
    data = []
    for _ in range(size):
        # 混合类型:整数、浮点数、字符串
        choice = random.randint(0, 2)
        if choice == 0:
            data.append(random.randint(-10000, 10000))
        elif choice == 1:
            data.append(round(random.uniform(-1e6, 1e6), 4))
        else:
            data.append(''.join(random.choices(string.ascii_letters, k=5)))
    return data
小技巧:我在项目中遇到过一个问题——随机数据生成后没保存种子,结果 bug 复现不了。从那以后,我每次生成数据都会把种子和参数写进日志。

3.2 边界值数据:最容易翻车的地方

为什么边界值这么重要?因为大多数 bug 都藏在「临界点」上。我见过太多算法在中间值跑得飞起,一到边界就崩了。

常见的边界值类型:

数据类型 边界值示例 为什么重要
整数 0, 1, -1, MAX_INT, MIN_INT 溢出、除零、符号问题
浮点数 0.0, -0.0, INF, NaN 精度丢失、特殊值处理
字符串 空串, 单字符, 最大长度 内存分配、索引越界
数组 空数组, 单元素, 满数组 循环边界、指针操作
避坑指南:我曾经在验证一个排序算法时,只测了正数数组。结果上线后用户输入了负数,算法直接死循环。后来我养成了习惯——边界值测试必须包含「零、负值、最大值」这三件套。

3.3 特殊场景数据构造:模拟真实世界的「脏数据」

真实世界的数据,可不像教科书那么干净。你想想看,用户可能输入什么?乱码、空值、超长字符串、甚至二进制数据……

我建议,特殊场景数据至少包含以下几类:

  • 空值/缺失值:None、null、undefined
  • 异常格式:日期格式错误、编码不一致
  • 重复数据:完全相同的记录出现多次
  • 极端比例:比如 99% 相同 + 1% 不同
  • 并发写入:多线程同时修改同一数据

来看一个构造特殊场景数据的例子:

def generate_edge_cases():
    cases = []
    # 空值场景
    cases.append(None)
    cases.append([])
    cases.append("")
    
    # 异常格式
    cases.append("2024-13-01")  # 非法月份
    cases.append("abc123!@#")   # 特殊字符
    
    # 极端比例
    cases.append([1] * 999 + [2])  # 99.9% 相同
    
    # 超大值
    cases.append(10**100)
    cases.append(-10**100)
    
    return cases
核心观点:测试数据生成不是「随便写几个数」,而是有策略地覆盖正常、边界、异常三个维度。我见过太多项目因为数据生成不充分,上线后出各种幺蛾子。

3.4 知识体系总览

下面这张图,是我自己总结的数据生成知识框架。每次做测试前,我都会对照着检查一遍:

测试数据生成 随机数据 均匀分布 可复现种子 数量可控 边界值数据 零值/空值 最大/最小值 溢出值 特殊场景数据 异常格式 重复数据 并发场景 三者结合 = 完整的测试数据覆盖

这张图其实就说明了一个道理:随机数据负责广度,边界值负责深度,特殊场景负责「意外」。三者缺一不可。

3.5 实战中的一些经验

最后分享几个我踩过的坑:

  • 别只测「好看」的数据——我见过有人专门挑算法能跑通的数据来测,这跟没测一样
  • 数据量要够大——小数据量下算法可能没问题,一上百万级就暴露了
  • 别忘了清理测试数据——有一次我生成的测试数据没清理,直接混进了生产库……嗯,那场面
我的习惯:每次写测试数据生成代码时,我都会先问自己三个问题——「正常情况能跑吗?」「边界情况会崩吗?」「异常情况怎么处理?」。问完这三个问题,数据生成方案基本就稳了。

好了,这一章的内容就到这里。数据生成看起来简单,但真正做好需要花心思。下一章我们会聊聊如何搭建测试场景,到时候见。

可可精品资料库