📌目录
- [⚖️ 白盒测试:深入代码内部的测试方法](#⚖️ 白盒测试:深入代码内部的测试方法)

⚖️ 白盒测试:深入代码内部的测试方法
白盒测试是一种基于程序内部逻辑结构的测试方法,它要求测试人员了解程序的内部实现,通过检查代码的逻辑路径来设计测试用例。本文将详细介绍白盒测试的概念、方法、技术和应用。

🎯 一、白盒测试概述
(一)白盒测试定义
白盒测试(White Box Testing)又称结构测试、逻辑驱动测试,是一种基于程序内部逻辑结构的测试方法。
白盒测试特点:
#mermaid-svg-rcLHabWc5S43JYNg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-rcLHabWc5S43JYNg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-rcLHabWc5S43JYNg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-rcLHabWc5S43JYNg .error-icon{fill:#552222;}#mermaid-svg-rcLHabWc5S43JYNg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-rcLHabWc5S43JYNg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-rcLHabWc5S43JYNg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-rcLHabWc5S43JYNg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-rcLHabWc5S43JYNg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-rcLHabWc5S43JYNg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-rcLHabWc5S43JYNg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-rcLHabWc5S43JYNg .marker{fill:#333333;stroke:#333333;}#mermaid-svg-rcLHabWc5S43JYNg .marker.cross{stroke:#333333;}#mermaid-svg-rcLHabWc5S43JYNg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-rcLHabWc5S43JYNg p{margin:0;}#mermaid-svg-rcLHabWc5S43JYNg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-rcLHabWc5S43JYNg .cluster-label text{fill:#333;}#mermaid-svg-rcLHabWc5S43JYNg .cluster-label span{color:#333;}#mermaid-svg-rcLHabWc5S43JYNg .cluster-label span p{background-color:transparent;}#mermaid-svg-rcLHabWc5S43JYNg .label text,#mermaid-svg-rcLHabWc5S43JYNg span{fill:#333;color:#333;}#mermaid-svg-rcLHabWc5S43JYNg .node rect,#mermaid-svg-rcLHabWc5S43JYNg .node circle,#mermaid-svg-rcLHabWc5S43JYNg .node ellipse,#mermaid-svg-rcLHabWc5S43JYNg .node polygon,#mermaid-svg-rcLHabWc5S43JYNg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-rcLHabWc5S43JYNg .rough-node .label text,#mermaid-svg-rcLHabWc5S43JYNg .node .label text,#mermaid-svg-rcLHabWc5S43JYNg .image-shape .label,#mermaid-svg-rcLHabWc5S43JYNg .icon-shape .label{text-anchor:middle;}#mermaid-svg-rcLHabWc5S43JYNg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-rcLHabWc5S43JYNg .rough-node .label,#mermaid-svg-rcLHabWc5S43JYNg .node .label,#mermaid-svg-rcLHabWc5S43JYNg .image-shape .label,#mermaid-svg-rcLHabWc5S43JYNg .icon-shape .label{text-align:center;}#mermaid-svg-rcLHabWc5S43JYNg .node.clickable{cursor:pointer;}#mermaid-svg-rcLHabWc5S43JYNg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-rcLHabWc5S43JYNg .arrowheadPath{fill:#333333;}#mermaid-svg-rcLHabWc5S43JYNg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-rcLHabWc5S43JYNg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-rcLHabWc5S43JYNg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rcLHabWc5S43JYNg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-rcLHabWc5S43JYNg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rcLHabWc5S43JYNg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-rcLHabWc5S43JYNg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-rcLHabWc5S43JYNg .cluster text{fill:#333;}#mermaid-svg-rcLHabWc5S43JYNg .cluster span{color:#333;}#mermaid-svg-rcLHabWc5S43JYNg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-rcLHabWc5S43JYNg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-rcLHabWc5S43JYNg rect.text{fill:none;stroke-width:0;}#mermaid-svg-rcLHabWc5S43JYNg .icon-shape,#mermaid-svg-rcLHabWc5S43JYNg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rcLHabWc5S43JYNg .icon-shape p,#mermaid-svg-rcLHabWc5S43JYNg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-rcLHabWc5S43JYNg .icon-shape .label rect,#mermaid-svg-rcLHabWc5S43JYNg .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rcLHabWc5S43JYNg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-rcLHabWc5S43JYNg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-rcLHabWc5S43JYNg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 白盒测试
了解内部结构
基于代码逻辑
检查路径覆盖
验证内部行为
查看源代码
理解控制流
分析判定条件
设计测试用例
语句覆盖
判定覆盖
条件覆盖
路径覆盖
验证逻辑正确性
发现内部缺陷
(二)白盒测试与黑盒测试对比
白盒测试与黑盒测试对比:
| 对比维度 | 白盒测试 | 黑盒测试 |
|---|---|---|
| 测试依据 | 内部逻辑结构 | 需求规格说明 |
| 测试视角 | 程序内部 | 程序外部 |
| 是否需要代码 | 需要 | 不需要 |
| 测试设计 | 基于代码逻辑 | 基于功能需求 |
| 覆盖标准 | 代码覆盖率 | 功能覆盖率 |
| 适用阶段 | 单元测试 | 系统测试、验收测试 |
| 测试人员 | 开发人员 | 测试人员、用户 |
📦 二、逻辑覆盖技术
(一)覆盖技术概述
逻辑覆盖技术是白盒测试的核心方法,用于衡量测试的完整性。
覆盖技术层次:
| 覆盖类型 | 覆盖强度 | 说明 |
|---|---|---|
| 语句覆盖 | 最弱 | 每条语句至少执行一次 |
| 判定覆盖 | 较弱 | 每个判定的真假都执行 |
| 条件覆盖 | 较弱 | 每个条件的真假都执行 |
| 判定/条件覆盖 | 中等 | 同时满足判定和条件覆盖 |
| 条件组合覆盖 | 较强 | 所有条件组合都执行 |
| 路径覆盖 | 最强 | 每条路径都执行 |
(二)语句覆盖
语句覆盖要求每条语句至少执行一次。
语句覆盖示例:
python
# 语句覆盖示例
# 被测程序
def calculate_bonus(salary, performance):
"""计算奖金"""
bonus = 0
if performance > 80:
bonus = salary * 0.2
if performance > 90:
bonus = salary * 0.3
return bonus
# 语句覆盖分析
def statement_coverage():
"""语句覆盖分析"""
print("语句覆盖分析")
print("=" * 70)
print("\n程序语句:")
print("-" * 70)
print(" S1: bonus = 0")
print(" S2: if performance > 80:")
print(" S3: bonus = salary * 0.2")
print(" S4: if performance > 90:")
print(" S5: bonus = salary * 0.3")
print(" S6: return bonus")
print("\n语句覆盖要求:")
print(" 每条语句至少执行一次")
print("\n测试用例设计:")
print("-" * 70)
# 测试用例
test_cases = [
{
"id": "TC1",
"input": {"salary": 10000, "performance": 95},
"execution": ["S1", "S2", "S3", "S4", "S5", "S6"],
"output": 3000,
"coverage": "覆盖所有语句"
}
]
for tc in test_cases:
print(f"\n测试用例:{tc['id']}")
print(f" 输入: salary={tc['input']['salary']}, performance={tc['input']['performance']}")
print(f" 执行路径: {' → '.join(tc['execution'])}")
print(f" 输出: {tc['output']}")
print(f" 覆盖情况: {tc['coverage']}")
print("\n语句覆盖分析:")
print("-" * 70)
print(" ✓ S1: bonus = 0 被执行")
print(" ✓ S2: if performance > 80 被执行")
print(" ✓ S3: bonus = salary * 0.2 被执行")
print(" ✓ S4: if performance > 90 被执行")
print(" ✓ S5: bonus = salary * 0.3 被执行")
print(" ✓ S6: return bonus 被执行")
print("\n 语句覆盖率: 100% (6/6)")
print("\n语句覆盖的不足:")
print(" - 不能发现判定条件的错误")
print(" - 不能发现条件组合的错误")
print(" - 测试强度较弱")
statement_coverage()
(三)判定覆盖
判定覆盖要求每个判定的真假分支都至少执行一次。
判定覆盖示例:
python
# 判定覆盖示例
# 被测程序
def process_order(quantity, price):
"""处理订单"""
if quantity > 0 and price > 0:
total = quantity * price
status = "有效"
else:
total = 0
status = "无效"
return {"total": total, "status": status}
# 判定覆盖分析
def decision_coverage():
"""判定覆盖分析"""
print("判定覆盖分析")
print("=" * 70)
print("\n程序判定:")
print("-" * 70)
print(" D1: if quantity > 0 and price > 0")
print(" 真分支: total = quantity * price, status = '有效'")
print(" 假分支: total = 0, status = '无效'")
print("\n判定覆盖要求:")
print(" 每个判定的真假分支都至少执行一次")
print("\n测试用例设计:")
print("-" * 70)
test_cases = [
{
"id": "TC1",
"input": {"quantity": 10, "price": 100},
"decision": "D1为真",
"output": {"total": 1000, "status": "有效"},
"branch": "真分支"
},
{
"id": "TC2",
"input": {"quantity": 0, "price": 100},
"decision": "D1为假",
"output": {"total": 0, "status": "无效"},
"branch": "假分支"
}
]
for tc in test_cases:
print(f"\n测试用例:{tc['id']}")
print(f" 输入: quantity={tc['input']['quantity']}, price={tc['input']['price']}")
print(f" 判定结果: {tc['decision']}")
print(f" 执行分支: {tc['branch']}")
print(f" 输出: {tc['output']}")
print("\n判定覆盖分析:")
print("-" * 70)
print(" 判定D1:")
print(" ✓ 真分支: TC1执行")
print(" ✓ 假分支: TC2执行")
print("\n 判定覆盖率: 100% (2/2)")
print("\n判定覆盖的不足:")
print(" - 不能保证条件覆盖")
print(" - 例如:TC1中quantity>0为真,price>0也为真")
print(" - 但quantity>0为假、price>0为真的情况未测试")
decision_coverage()
(四)条件覆盖
条件覆盖要求每个条件的所有可能取值都至少执行一次。
条件覆盖示例:
python
# 条件覆盖示例
# 被测程序
def check_access(age, has_id):
"""检查访问权限"""
if age >= 18 and has_id:
access = "允许"
else:
access = "拒绝"
return access
# 条件覆盖分析
def condition_coverage():
"""条件覆盖分析"""
print("条件覆盖分析")
print("=" * 70)
print("\n程序条件:")
print("-" * 70)
print(" 判定: if age >= 18 and has_id")
print(" 条件C1: age >= 18")
print(" 条件C2: has_id")
print("\n条件覆盖要求:")
print(" 每个条件的所有可能取值都至少执行一次")
print("\n条件取值:")
print("-" * 70)
print(" C1: age >= 18")
print(" 真: age = 20")
print(" 假: age = 16")
print(" C2: has_id")
print(" 真: has_id = True")
print(" 假: has_id = False")
print("\n测试用例设计:")
print("-" * 70)
test_cases = [
{
"id": "TC1",
"input": {"age": 20, "has_id": True},
"conditions": {"C1": "真", "C2": "真"},
"output": "允许"
},
{
"id": "TC2",
"input": {"age": 16, "has_id": False},
"conditions": {"C1": "假", "C2": "假"},
"output": "拒绝"
}
]
for tc in test_cases:
print(f"\n测试用例:{tc['id']}")
print(f" 输入: age={tc['input']['age']}, has_id={tc['input']['has_id']}")
print(f" 条件取值: C1={tc['conditions']['C1']}, C2={tc['conditions']['C2']}")
print(f" 输出: {tc['output']}")
print("\n条件覆盖分析:")
print("-" * 70)
print(" 条件C1 (age >= 18):")
print(" ✓ 真值: TC1执行")
print(" ✓ 假值: TC2执行")
print(" 条件C2 (has_id):")
print(" ✓ 真值: TC1执行")
print(" ✓ 假值: TC2执行")
print("\n 条件覆盖率: 100% (4/4)")
print("\n条件覆盖的不足:")
print(" - 不能保证判定覆盖")
print(" - TC1: C1真, C2真 → 判定为真")
print(" - TC2: C1假, C2假 → 判定为假")
print(" - 但C1真C2假、C1假C2真的组合未测试")
condition_coverage()
(五)判定/条件覆盖
判定/条件覆盖要求同时满足判定覆盖和条件覆盖。
判定/条件覆盖示例:
python
# 判定/条件覆盖示例
# 被测程序
def calculate_shipping(weight, is_express):
"""计算运费"""
if weight > 10 or is_express:
if weight > 20:
shipping = 50
else:
shipping = 30
else:
shipping = 10
return shipping
# 判定/条件覆盖分析
def decision_condition_coverage():
"""判定/条件覆盖分析"""
print("判定/条件覆盖分析")
print("=" * 70)
print("\n程序判定和条件:")
print("-" * 70)
print(" 判定D1: if weight > 10 or is_express")
print(" 条件C1: weight > 10")
print(" 条件C2: is_express")
print(" 判定D2: if weight > 20")
print(" 条件C3: weight > 20")
print("\n判定/条件覆盖要求:")
print(" 同时满足判定覆盖和条件覆盖")
print("\n测试用例设计:")
print("-" * 70)
test_cases = [
{
"id": "TC1",
"input": {"weight": 25, "is_express": True},
"conditions": {"C1": "真", "C2": "真", "C3": "真"},
"decisions": {"D1": "真", "D2": "真"},
"output": 50
},
{
"id": "TC2",
"input": {"weight": 5, "is_express": False},
"conditions": {"C1": "假", "C2": "假", "C3": "假"},
"decisions": {"D1": "假", "D2": "N/A"},
"output": 10
},
{
"id": "TC3",
"input": {"weight": 15, "is_express": False},
"conditions": {"C1": "真", "C2": "假", "C3": "假"},
"decisions": {"D1": "真", "D2": "假"},
"output": 30
}
]
for tc in test_cases:
print(f"\n测试用例:{tc['id']}")
print(f" 输入: weight={tc['input']['weight']}, is_express={tc['input']['is_express']}")
print(f" 条件: C1={tc['conditions']['C1']}, C2={tc['conditions']['C2']}, C3={tc['conditions']['C3']}")
print(f" 判定: D1={tc['decisions']['D1']}, D2={tc['decisions']['D2']}")
print(f" 输出: {tc['output']}")
print("\n覆盖分析:")
print("-" * 70)
print(" 判定覆盖:")
print(" ✓ D1真: TC1, TC3执行")
print(" ✓ D1假: TC2执行")
print(" ✓ D2真: TC1执行")
print(" ✓ D2假: TC3执行")
print(" 条件覆盖:")
print(" ✓ C1真: TC1, TC3执行")
print(" ✓ C1假: TC2执行")
print(" ✓ C2真: TC1执行")
print(" ✓ C2假: TC2, TC3执行")
print(" ✓ C3真: TC1执行")
print(" ✓ C3假: TC2, TC3执行")
print("\n 判定覆盖率: 100%")
print(" 条件覆盖率: 100%")
decision_condition_coverage()
(六)条件组合覆盖
条件组合覆盖要求所有条件的各种可能组合都至少执行一次。
条件组合覆盖示例:
python
# 条件组合覆盖示例
# 被测程序
def validate_user(username, password, age):
"""验证用户"""
if len(username) >= 6 and len(password) >= 8 and age >= 18:
result = "有效用户"
else:
result = "无效用户"
return result
# 条件组合覆盖分析
def multiple_condition_coverage():
"""条件组合覆盖分析"""
print("条件组合覆盖分析")
print("=" * 70)
print("\n程序条件:")
print("-" * 70)
print(" 判定: if len(username) >= 6 and len(password) >= 8 and age >= 18")
print(" 条件C1: len(username) >= 6")
print(" 条件C2: len(password) >= 8")
print(" 条件C3: age >= 18")
print("\n条件组合覆盖要求:")
print(" 所有条件的各种可能组合都至少执行一次")
print("\n条件组合数:")
print(" 3个条件,每个条件2个取值")
print(" 组合数 = 2^3 = 8种")
print("\n条件组合列表:")
print("-" * 70)
combinations = [
{"C1": "真", "C2": "真", "C3": "真", "username": "user01", "password": "password1", "age": 20},
{"C1": "真", "C2": "真", "C3": "假", "username": "user01", "password": "password1", "age": 16},
{"C1": "真", "C2": "假", "C3": "真", "username": "user01", "password": "pass1", "age": 20},
{"C1": "真", "C2": "假", "C3": "假", "username": "user01", "password": "pass1", "age": 16},
{"C1": "假", "C2": "真", "C3": "真", "username": "user", "password": "password1", "age": 20},
{"C1": "假", "C2": "真", "C3": "假", "username": "user", "password": "password1", "age": 16},
{"C1": "假", "C2": "假", "C3": "真", "username": "user", "password": "pass1", "age": 20},
{"C1": "假", "C2": "假", "C3": "假", "username": "user", "password": "pass1", "age": 16},
]
for i, combo in enumerate(combinations, 1):
print(f"\n组合{i}:")
print(f" C1={combo['C1']}, C2={combo['C2']}, C3={combo['C3']}")
print(f" 测试数据: username='{combo['username']}', password='{combo['password']}', age={combo['age']}")
print("\n条件组合覆盖分析:")
print("-" * 70)
print(f" 总组合数: 8")
print(f" 已覆盖: 8")
print(f" 覆盖率: 100%")
print("\n条件组合覆盖的特点:")
print(" - 测试强度强")
print(" - 可以发现条件组合的错误")
print(" - 测试用例数量随条件数指数增长")
print(" - 对于复杂程序,测试成本较高")
multiple_condition_coverage()
🌐 三、路径测试
(一)路径测试概述
路径测试要求覆盖程序中的所有可能路径。
路径测试概念:
渲染错误: Mermaid 渲染失败: Parse error on line 11: ... C --> C1V(G) = E - N + 2 ---------------------^ Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'PS'
(二)控制流图
控制流图是描述程序控制流程的图形表示。
控制流图示例:
python
# 控制流图示例
# 被测程序
def process_data(x, y):
"""数据处理"""
# 节点1
result = 0
# 节点2:判定
if x > 0:
# 节点3
if y > 0:
# 节点4
result = x + y
else:
# 节点5
result = x - y
else:
# 节点6
if y > 0:
# 节点7
result = -x + y
else:
# 节点8
result = -x - y
# 节点9
return result
# 控制流图分析
def control_flow_graph():
"""控制流图分析"""
print("控制流图分析")
print("=" * 70)
print("\n程序控制流图:")
print("-" * 70)
print("""
┌─────────┐
│ 节点1 │ result = 0
└────┬────┘
│
┌────▼────┐
│ 节点2 │ if x > 0
└────┬────┘
│
┌─────┴─────┐
│ │
┌────▼────┐ ┌────▼────┐
│ 节点3 │ │ 节点6 │
│ if y>0 │ │ if y>0 │
└────┬────┘ └────┬────┘
│ │
┌────┴────┐ ┌────┴────┐
│ │ │ │
┌──▼──┐ ┌──▼──┐ ┌──▼──┐ ┌──▼──┐
│节点4│ │节点5│ │节点7│ │节点8│
│x+y │ │x-y │ │-x+y │ │-x-y │
└──┬──┘ └──┬──┘ └──┬──┘ └──┬──┘
│ │ │ │
└────┬───┴───────┴────────┘
│
┌────▼────┐
│ 节点9 │ return result
└─────────┘
""")
print("\n控制流图要素:")
print("-" * 70)
print(" 节点(N): 9个")
print(" 边(E): 11条")
print(" 判定节点: 3个 (节点2, 3, 6)")
print("\n圈复杂度计算:")
print("-" * 70)
print(" 方法1: V(G) = E - N + 2")
print(" V(G) = 11 - 9 + 2 = 4")
print()
print(" 方法2: V(G) = 判定节点数 + 1")
print(" V(G) = 3 + 1 = 4")
print()
print(" 圈复杂度: 4")
print(" 含义: 需要至少4条基本路径")
control_flow_graph()
(三)基本路径测试
基本路径测试基于圈复杂度设计测试用例。
基本路径测试示例:
python
# 基本路径测试示例
# 被测程序
def calculate_grade(score):
"""计算成绩等级"""
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
elif score >= 60:
grade = "D"
else:
grade = "F"
return grade
# 基本路径测试
def basic_path_testing():
"""基本路径测试"""
print("基本路径测试")
print("=" * 70)
print("\n程序控制流图:")
print("-" * 70)
print("""
节点1: score输入
│
节点2: if score >= 90
│
┌────┴────┐
│ │
节点3 节点4: elif score >= 80
grade=A │
│ ┌───┴───┐
│ │ │
│ 节点5 节点6: elif score >= 70
│ grade=B │
│ │ ┌───┴───┐
│ │ │ │
│ │ 节点7 节点8: elif score >= 60
│ │ grade=C │
│ │ │ ┌───┴───┐
│ │ │ │ │
│ │ │ 节点9 节点10
│ │ │ grade=D grade=F
│ │ │ │ │
└──────┴────┴────┴───────┘
│
节点11: return grade
""")
print("\n圈复杂度计算:")
print("-" * 70)
print(" 判定节点数: 4")
print(" V(G) = 4 + 1 = 5")
print(" 需要5条基本路径")
print("\n基本路径识别:")
print("-" * 70)
paths = [
{
"id": "路径1",
"nodes": [1, 2, 3, 11],
"condition": "score >= 90",
"test_input": 95,
"expected_output": "A"
},
{
"id": "路径2",
"nodes": [1, 2, 4, 5, 11],
"condition": "80 <= score < 90",
"test_input": 85,
"expected_output": "B"
},
{
"id": "路径3",
"nodes": [1, 2, 4, 6, 7, 11],
"condition": "70 <= score < 80",
"test_input": 75,
"expected_output": "C"
},
{
"id": "路径4",
"nodes": [1, 2, 4, 6, 8, 9, 11],
"condition": "60 <= score < 70",
"test_input": 65,
"expected_output": "D"
},
{
"id": "路径5",
"nodes": [1, 2, 4, 6, 8, 10, 11],
"condition": "score < 60",
"test_input": 50,
"expected_output": "F"
}
]
for path in paths:
print(f"\n{path['id']}:")
print(f" 节点序列: {' → '.join(map(str, path['nodes']))}")
print(f" 条件: {path['condition']}")
print(f" 测试输入: {path['test_input']}")
print(f" 预期输出: {path['expected_output']}")
print("\n测试执行:")
print("-" * 70)
for path in paths:
result = calculate_grade(path['test_input'])
status = "通过" if result == path['expected_output'] else "失败"
print(f" {path['id']}: score={path['test_input']} → grade={result} [{status}]")
print("\n基本路径测试总结:")
print("-" * 70)
print(f" 圈复杂度: 5")
print(f" 基本路径数: 5")
print(f" 测试用例数: 5")
print(f" 路径覆盖率: 100%")
basic_path_testing()
(四)路径覆盖
路径覆盖要求覆盖程序中的所有可能路径。
路径覆盖示例:
python
# 路径覆盖示例
# 被测程序
def complex_function(a, b):
"""复杂函数"""
result = 0
if a > 0:
if b > 0:
result = 1 # 路径1
else:
result = 2 # 路径2
else:
if b > 0:
result = 3 # 路径3
else:
result = 4 # 路径4
return result
# 路径覆盖分析
def path_coverage():
"""路径覆盖分析"""
print("路径覆盖分析")
print("=" * 70)
print("\n程序路径分析:")
print("-" * 70)
print("""
路径1: a>0, b>0 → result=1
路径2: a>0, b<=0 → result=2
路径3: a<=0, b>0 → result=3
路径4: a<=0, b<=0 → result=4
总路径数: 4条
""")
print("\n路径覆盖要求:")
print(" 覆盖所有可能的路径")
print("\n测试用例设计:")
print("-" * 70)
test_cases = [
{
"id": "TC1",
"input": {"a": 5, "b": 3},
"path": "路径1",
"conditions": "a>0, b>0",
"expected": 1
},
{
"id": "TC2",
"input": {"a": 5, "b": -3},
"path": "路径2",
"conditions": "a>0, b<=0",
"expected": 2
},
{
"id": "TC3",
"input": {"a": -5, "b": 3},
"path": "路径3",
"conditions": "a<=0, b>0",
"expected": 3
},
{
"id": "TC4",
"input": {"a": -5, "b": -3},
"path": "路径4",
"conditions": "a<=0, b<=0",
"expected": 4
}
]
for tc in test_cases:
print(f"\n测试用例:{tc['id']}")
print(f" 输入: a={tc['input']['a']}, b={tc['input']['b']}")
print(f" 覆盖路径: {tc['path']}")
print(f" 条件: {tc['conditions']}")
print(f" 预期输出: {tc['expected']}")
print("\n测试执行:")
print("-" * 70)
for tc in test_cases:
result = complex_function(tc['input']['a'], tc['input']['b'])
status = "通过" if result == tc['expected'] else "失败"
print(f" {tc['id']}: a={tc['input']['a']}, b={tc['input']['b']} → {result} [{status}]")
print("\n路径覆盖总结:")
print("-" * 70)
print(f" 总路径数: 4")
print(f" 已覆盖: 4")
print(f" 路径覆盖率: 100%")
print("\n路径覆盖的特点:")
print(" - 最强的覆盖标准")
print(" - 可以发现所有路径上的错误")
print(" - 对于复杂程序,路径数量可能非常大")
print(" - 实际应用中通常使用基本路径测试")
path_coverage()
💡 四、白盒测试应用
(一)应用场景
白盒测试应用场景:
| 场景 | 说明 |
|---|---|
| 单元测试 | 测试单个函数或方法 |
| 关键代码 | 测试安全、金融等关键代码 |
| 代码审查 | 辅助代码审查过程 |
| 重构验证 | 验证代码重构的正确性 |
| 性能优化 | 分析代码性能瓶颈 |
(二)应用示例
白盒测试综合应用:
python
# 白盒测试综合应用
# 被测程序:银行账户系统
class BankAccount:
"""银行账户"""
def __init__(self, account_id, initial_balance=0):
self.account_id = account_id
self.balance = initial_balance
self.transaction_history = []
def deposit(self, amount):
"""存款"""
if amount <= 0:
return {"success": False, "message": "存款金额必须大于0"}
if amount > 100000:
return {"success": False, "message": "单笔存款不能超过10万"}
self.balance += amount
self.transaction_history.append({
"type": "deposit",
"amount": amount,
"balance": self.balance
})
return {"success": True, "message": "存款成功", "balance": self.balance}
def withdraw(self, amount):
"""取款"""
if amount <= 0:
return {"success": False, "message": "取款金额必须大于0"}
if amount > self.balance:
return {"success": False, "message": "余额不足"}
if amount > 50000:
return {"success": False, "message": "单笔取款不能超过5万"}
self.balance -= amount
self.transaction_history.append({
"type": "withdraw",
"amount": amount,
"balance": self.balance
})
return {"success": False, "message": "取款成功", "balance": self.balance}
# 白盒测试
def white_box_testing_application():
"""白盒测试应用"""
print("白盒测试综合应用")
print("=" * 70)
print("\n被测程序:BankAccount类")
print("-" * 70)
print(" 方法1: deposit(amount)")
print(" 方法2: withdraw(amount)")
print("\n\n1. deposit方法分析")
print("=" * 70)
print("\n控制流分析:")
print("-" * 70)
print("""
路径1: amount <= 0 → 返回错误
路径2: amount > 100000 → 返回错误
路径3: 0 < amount <= 100000 → 存款成功
判定节点: 2
圈复杂度: 3
""")
print("\n测试用例设计(基本路径测试):")
print("-" * 70)
deposit_tests = [
{"amount": -100, "path": "路径1", "expected": "错误"},
{"amount": 200000, "path": "路径2", "expected": "错误"},
{"amount": 1000, "path": "路径3", "expected": "成功"},
]
account = BankAccount("ACC001", 10000)
for i, test in enumerate(deposit_tests, 1):
result = account.deposit(test["amount"])
print(f" TC{i}: amount={test['amount']}")
print(f" 路径: {test['path']}")
print(f" 结果: {result['message']}")
print("\n\n2. withdraw方法分析")
print("=" * 70)
print("\n控制流分析:")
print("-" * 70)
print("""
路径1: amount <= 0 → 返回错误
路径2: amount > balance → 返回错误
路径3: amount > 50000 → 返回错误
路径4: 0 < amount <= min(balance, 50000) → 取款成功
判定节点: 3
圈复杂度: 4
""")
print("\n测试用例设计(基本路径测试):")
print("-" * 70)
withdraw_tests = [
{"amount": -100, "path": "路径1", "expected": "错误"},
{"amount": 100000, "path": "路径2", "expected": "错误"},
{"amount": 60000, "path": "路径3", "expected": "错误"},
{"amount": 1000, "path": "路径4", "expected": "成功"},
]
account2 = BankAccount("ACC002", 10000)
for i, test in enumerate(withdraw_tests, 1):
result = account2.withdraw(test["amount"])
print(f" TC{i}: amount={test['amount']}")
print(f" 路径: {test['path']}")
print(f" 结果: {result['message']}")
print("\n\n3. 测试覆盖率统计")
print("=" * 70)
coverage = {
"deposit方法": {
"语句覆盖": "100%",
"判定覆盖": "100%",
"条件覆盖": "100%",
"路径覆盖": "100%"
},
"withdraw方法": {
"语句覆盖": "100%",
"判定覆盖": "100%",
"条件覆盖": "100%",
"路径覆盖": "100%"
}
}
for method, rates in coverage.items():
print(f"\n{method}:")
for coverage_type, rate in rates.items():
print(f" {coverage_type}: {rate}")
print("\n\n4. 发现的问题")
print("=" * 70)
issues = [
{
"method": "withdraw",
"line": "return语句",
"issue": "取款成功时返回success=False",
"severity": "严重",
"suggestion": "修改为return {'success': True, ...}"
}
]
for i, issue in enumerate(issues, 1):
print(f"\n问题{i}:")
print(f" 方法: {issue['method']}")
print(f" 位置: {issue['line']}")
print(f" 问题: {issue['issue']}")
print(f" 严重程度: {issue['severity']}")
print(f" 建议: {issue['suggestion']}")
white_box_testing_application()
📝 总结
白盒测试是一种基于程序内部逻辑结构的测试方法。
🎯 白盒测试概念:
- 了解程序内部结构
- 基于代码逻辑设计测试
- 检查路径覆盖情况
- 验证内部行为正确性
📦 逻辑覆盖技术:
- 语句覆盖:每条语句至少执行一次(最弱)
- 判定覆盖:每个判定的真假都执行
- 条件覆盖:每个条件的真假都执行
- 判定/条件覆盖:同时满足判定和条件覆盖
- 条件组合覆盖:所有条件组合都执行
- 路径覆盖:每条路径都执行(最强)
🌐 路径测试:
- 控制流图:描述程序控制流程
- 圈复杂度:V(G) = E - N + 2 = 判定节点数 + 1
- 基本路径测试:基于圈复杂度设计测试用例
- 路径覆盖:覆盖所有可能路径
💡 应用场景:
- 单元测试:测试单个函数或方法
- 关键代码:测试安全、金融等关键代码
- 代码审查:辅助代码审查过程
- 重构验证:验证代码重构的正确性
核心启示:白盒测试是深入代码内部的测试方法,可以发现黑盒测试难以发现的问题。在实际工作中,我们需要注意:第一,了解各种覆盖标准的强度和适用场景;第二,根据代码复杂度选择合适的覆盖标准;第三,使用工具辅助计算圈复杂度和生成测试用例;第四,结合黑盒测试,全面保证软件质量;第五,白盒测试成本较高,应重点用于关键代码。记住:白盒测试是保证代码质量的重要手段,但需要权衡测试成本和收益。