前置知识: 软件工程与测试

边界值分析

5 min中级

边界值分析方法:边界条件识别、测试值选取、健壮性测试与实战应用详解。

1. 边界值分析原理

1.1 基本概念

边界值分析是基于”缺陷往往出现在输入边界”的经验,重点测试边界条件及其附近值。 它把「测哪里」从等价类的整个区间收敛到几个点,是等价类划分最常用的搭档。

1.2 为什么测试边界

大量缺陷发生在边界条件上:

  • 程序员使用 < 而非 <=
  • 数组索引从 0 还是 1 开始
  • 循环条件 off-by-one 错误

类比:边界像悬崖边缘——站在正中间怎么走都安全,几乎所有事故都发生在 离崖边一步的地方。代码同理:if (x > 0) 这类逻辑,只有在 x 逼近 0 时 才会暴露写错比较符的问题。

1.3 与等价类划分的关系

边界值分析是等价类划分的补充,在等价类边界处选取测试值。标准流程: 先划分有效/无效等价类(见「等价类划分」),再在每个等价类的边界与 边界两侧取代表值。

2. 边界值选取

2.1 基本边界值

对于范围 [a,b][a, b]:

值描述
a−1a - 1刚好小于下界
aa下界
a+1a + 1刚好大于下界
正常值范围内任意值
b−1b - 1刚好小于上界
bb上界
b+1b + 1刚好大于上界

2.2 示例:年龄 1-120

值类型预期结果
0无效(小于下界)错误
1边界(下界)有效
2边界(下界+1)有效
60正常值有效
119边界(上界-1)有效
120边界(上界)有效
121无效(大于上界)错误

2.3 健壮性边界值

在基本边界值基础上增加越界值:

值描述
a−2a - 2远小于下界
a−1a - 1刚小于下界
aa下界
a+1a + 1下界内侧
b−1b - 1上界内侧
bb上界
b+1b + 1刚大于上界
b+2b + 2远大于上界

3. 边界值类型

3.1 数值边界

场景边界值
范围 [0, 100]-1, 0, 1, 99, 100, 101
整数范围INT_MIN, INT_MIN+1, INT_MAX-1, INT_MAX
浮点数0.0, 最小正值, 最大正值

3.2 字符串边界

场景边界值
长度 1-50"", “a”, “ab”, 49字符, 50字符, 51字符
空字符串""
仅空格” ”

3.3 集合边界

场景边界值
列表索引0, 1, n-2, n-1
空列表[]
单元素[1]

3.4 时间边界

场景边界值
日期1月1日, 12月31日, 2月28/29日
时间00:00:00, 23:59:59
时区UTC-12, UTC+14

4. 边界值分析实例

4.1 实例1:密码强度

需求:密码长度 8-32,必须包含大小写字母和数字。

边界长度是否满足预期
7 字符7否拒绝
8 字符8是接受
9 字符9是接受
31 字符31是接受
32 字符32是接受
33 字符33否拒绝

4.2 实例2:文件上传

需求:文件大小 1KB-10MB,仅允许 jpg/png。

边界大小预期
0 KB空拒绝
1 KB下界接受
10 MB上界接受
10MB+1KB超上界拒绝
.gif非法类型拒绝
.jpg合法类型接受

4.3 实例3:分页查询

需求:每页 10-100 条,页码 ≥ 1。

参数边界值预期
page=0无效错误
page=1有效第一页
page=2有效第二页
size=9无效错误
size=10有效10条
size=100有效100条
size=101无效错误

5. 内部边界

5.1 数据结构边界

场景边界
数组空数组、单元素、满容量
栈空栈、满栈、单元素
队列空队列、满队列
哈希表空表、冲突、扩容阈值

5.2 状态边界

场景边界
状态机初始状态、最终状态
计数器0、最大值、溢出
超时刚好超时、刚好未超时

6. 边界值分析最佳实践

实践描述
识别所有边界显式+隐式边界
测试两侧边界内外都测
特殊值0、空、null、负数
数据类型边界INT_MAX、浮点精度
业务边界折扣阈值、等级分界
与等价类结合先划分再取边界

6.1 可运行的完整示例

import pytest

def withdraw_fee(months: int) -> int:
    """开户满 12 个月免手续费,否则收 2 元"""
    if months >= 12:
        return 0
    return 2

@pytest.mark.parametrize("months, fee", [
    (11, 2),    # 下界 - 1(边界外侧)
    (12, 0),    # 下界(边界本身)
    (13, 0),    # 下界 + 1(边界内侧)
    (-1, 2),    # 健壮性:非法输入也要有确定行为
])
def test_withdraw_fee(months, fee):
    assert withdraw_fee(months) == fee

注意断言的写法:每个参数只回答「这个边界值应得什么」,失败时 parametrize 的 id 会直接指出是哪条边界出了问题。

7. 常见陷阱

  • 只测边界本身,漏掉两侧:< 与 <= 的区别必须靠「边界-1 / 边界 / 边界+1」三个值才能区分,只测边界值会把这类缺陷全部放过。
  • 漏隐式边界:需求只写「金额上限 1 万」,隐式边界还有 0、负数、 小数位、极大值溢出。
  • 硬编码边界值:用例里写死 assert fee(months=12) == 0,需求改成 13 个月时要改十处;把边界常量提取出来统一引用。
  • 把边界值分析当穷举:每个边界 3-5 个代表值即可,目标是覆盖风险 而不是凑数量;组合爆炸的场景改用判定表或正交法。

小结

  • 初学者要点:每个区间边界取「边界-1、边界、边界+1」三个值;别忘了 0、空、负数、极大值这些通用特殊值;与等价类划分配合使用。
  • 进阶注意:隐式边界(数据类型上限、状态机转换点、超时临界)往往比 显式需求边界更容易藏缺陷;用参数化框架落地边界用例,一条断言对应 一个边界点,失败信息即可定位到具体边界。