软件测试是通过手动或自动化手段来运行或检验软件系统的过程,目的是发现软件缺陷、验证软件是否满足需求,并评估软件质量。
| 原则 | 说明 |
|---|
| 测试显示缺陷存在 | 测试只能证明缺陷存在,不能证明没有缺陷 |
| 穷尽测试不可能 | 无法测试所有输入组合,需用风险驱动优先级 |
| 尽早测试 | 缺陷越早发现,修复成本越低 |
| 缺陷集群性 | 少数模块往往包含大部分缺陷(二八定律) |
| 杀虫剂悖论 | 反复使用相同测试用例将无法发现新缺陷 |
| 测试依赖于上下文 | 不同系统需要不同的测试策略 |
| 无错误谬误 | 没有发现缺陷 ≠ 系统满足用户需求 |
修复成本
↑
│ ╱
│ ╱
│ ╱
│ ╱
│ ╱
│ ╱
│ ╱
│ ╱
│ ╱
└──────────────────────────────────→ 时间
需求 设计 编码 单元测试 集成测试 系统测试 发布后
| 类型 | 测试对象 | 执行者 | 关注点 |
|---|
| 单元测试 | 函数/方法/类 | 开发人员 | 代码逻辑正确性 |
| 集成测试 | 模块间接口 | 开发/测试 | 模块交互与数据传递 |
| 系统测试 | 完整系统 | 测试人员 | 功能、性能、安全 |
| 验收测试 | 交付系统 | 用户/客户 | 是否满足业务需求 |
| 类型 | 特点 | 是否需要代码 |
|---|
| 黑盒测试 | 关注输入输出,不关注内部 | 不需要 |
| 白盒测试 | 关注内部逻辑与结构 | 需要 |
| 灰盒测试 | 部分了解内部结构 | 部分需要 |
| 类型 | 说明 |
|---|
| 手动测试 | 人工执行测试用例 |
| 自动化测试 | 使用工具/脚本执行测试 |
| 类型 | 说明 |
|---|
| 功能测试 | 验证功能是否正确 |
| 性能测试 | 验证响应时间、吞吐量 |
| 安全测试 | 验证系统安全性 |
| 兼容性测试 | 验证多环境适配 |
| 易用性测试 | 验证用户体验 |
| 可靠性测试 | 验证长时间运行稳定性 |
将输入域划分为有效等价类和无效等价类,从每个等价类中选取代表值进行测试。
示例:用户年龄输入(18-60岁)
| 等价类 | 范围 | 测试数据 |
|---|
| 有效等价类 | 18 ≤ age ≤ 60 | 25 |
| 无效等价类-1 | age < 18 | 10 |
| 无效等价类-2 | age > 60 | 70 |
| 无效等价类-3 | 非数字输入 | ”abc” |
| 无效等价类-4 | 空输入 | "" |
# 等价类划分测试用例示例
import pytest
def validate_age(age_input):
"""验证年龄输入"""
if not age_input:
raise ValueError("年龄不能为空")
try:
age = int(age_input)
except ValueError:
raise ValueError("年龄必须为数字")
if age < 18:
raise ValueError("年龄不能小于18岁")
if age > 60:
raise ValueError("年龄不能大于60岁")
return age
# 有效等价类测试
def test_valid_age():
assert validate_age("25") == 25
assert validate_age("18") == 18 # 边界值
assert validate_age("60") == 60 # 边界值
# 无效等价类测试
def test_invalid_age_too_young():
with pytest.raises(ValueError, match="不能小于18岁"):
validate_age("10")
def test_invalid_age_too_old():
with pytest.raises(ValueError, match="不能大于60岁"):
validate_age("70")
def test_invalid_age_not_number():
with pytest.raises(ValueError, match="必须为数字"):
validate_age("abc")
def test_invalid_age_empty():
with pytest.raises(ValueError, match="不能为空"):
validate_age("")
边界值是缺陷最容易出现的区域,需对等价类边界进行重点测试。
示例:密码长度(6-20位)
| 边界值 | 数据 | 预期结果 |
|---|
| 小于下界 | 5位 | 失败 |
| 下界 | 6位 | 成功 |
| 下界+1 | 7位 | 成功 |
| 上界-1 | 19位 | 成功 |
| 上界 | 20位 | 成功 |
| 大于上界 | 21位 | 失败 |
def validate_password(password: str) -> bool:
"""验证密码长度 6-20 位"""
return 6 <= len(password) <= 20
class TestPasswordBoundary:
def test_below_min(self):
assert validate_password("12345") is False # 5位
def test_at_min(self):
assert validate_password("123456") is True # 6位
def test_above_min(self):
assert validate_password("1234567") is True # 7位
def test_below_max(self):
assert validate_password("1" * 19) is True # 19位
def test_at_max(self):
assert validate_password("1" * 20) is True # 20位
def test_above_max(self):
assert validate_password("1" * 21) is False # 21位
适用于多条件组合的测试场景,通过分析输入条件(因)与输出结果(果)的逻辑关系设计测试用例。
基本符号:
| 符号 | 含义 |
|---|
| 恒等 | 原因为真,结果为真 |
| 非 | 原因为真,结果为假 |
| 或 | 任一原因为真,结果为真 |
| 与 | 所有原因为真,结果为真 |
示例:购物折扣规则
- 条件1:会员用户(C1)
- 条件2:订单金额 > 200(C2)
- 条件3:使用优惠券(C3)
- 结果1:享受8折(E1):C1 AND C2
- 结果2:减20元(E2):C3
| 用例 | C1 | C2 | C3 | E1 | E2 |
|---|
| 1 | Y | Y | N | Y | N |
| 2 | Y | N | Y | N | Y |
| 3 | N | Y | Y | N | Y |
| 4 | Y | Y | Y | Y | Y |
| 5 | N | N | N | N | N |
基于经验和直觉推测可能存在的错误:
| 经验法则 | 示例 |
|---|
| 特殊字符输入 | <script>, 'OR 1=1-- |
| 空值和 null | 空字符串、null、undefined |
| 极端数据 | 超大文件、超长字符串 |
| 并发操作 | 同时提交、重复点击 |
| 网络异常 | 超时、断网、弱网 |
| 时区与日期 | 跨时区、闰年、2月29日 |
确保每条语句至少执行一次:
def calculate(a: int, b: int) -> int:
if a > 0: # 语句1
result = a + b # 语句2
else:
result = a - b # 语句3
return result # 语句4
# 语句覆盖:a=1, b=2 → 执行语句1,2,4(语句3未覆盖)
# 需要补充:a=-1, b=2 → 执行语句1,3,4
确保每个判定的真假分支至少执行一次:
# 分支覆盖测试用例
def test_calculate():
# True 分支
assert calculate(1, 2) == 3 # a > 0 → True
# False 分支
assert calculate(-1, 2) == -3 # a > 0 → False
确保所有可能路径至少执行一次:
def grade(score: int) -> str:
if score >= 90: # 判定1
return "优秀"
elif score >= 60: # 判定2
return "及格"
else:
return "不及格"
# 路径1: score=95 → 判定1=True
# 路径2: score=75 → 判定1=False, 判定2=True
# 路径3: score=45 → 判定1=False, 判定2=False
| 覆盖类型 | 强度 | 说明 |
|---|
| 语句覆盖 | 最弱 | 每条语句至少执行一次 |
| 分支覆盖 | 中等 | 每个分支至少执行一次 |
| 条件覆盖 | 较强 | 每个条件的真假各取一次 |
| 路径覆盖 | 最强 | 所有路径至少执行一次 |
| 字段 | 说明 |
|---|
| 用例编号 | TC-模块-序号,如 TC-LOGIN-001 |
| 用例标题 | 简明描述测试目的 |
| 前置条件 | 执行前需满足的条件 |
| 测试步骤 | 详细操作步骤 |
| 测试数据 | 输入数据 |
| 预期结果 | 期望的输出或行为 |
| 优先级 | 高/中/低 |
| 字段 | 内容 |
|---|
| 编号 | TC-LOGIN-001 |
| 标题 | 正确用户名和密码登录 |
| 前置条件 | 用户已注册,账号:admin / 密码:123456 |
| 步骤 | 1. 打开登录页面 2. 输入用户名 3. 输入密码 4. 点击登录 |
| 数据 | 用户名:admin,密码:123456 |
| 预期 | 登录成功,跳转首页 |
| 优先级 | 高 |
| 字段 | 内容 |
|---|
| 编号 | TC-LOGIN-002 |
| 标题 | 错误密码登录 |
| 前置条件 | 用户已注册 |
| 步骤 | 1. 打开登录页面 2. 输入用户名 3. 输入错误密码 4. 点击登录 |
| 数据 | 用户名:admin,密码:wrong |
| 预期 | 提示”用户名或密码错误” |
| 优先级 | 高 |
1. 引言
1.1 编写目的
1.2 项目背景
1.3 术语定义
2. 测试范围
2.1 测试对象
2.2 测试功能
2.3 不测试功能
3. 测试策略
3.1 测试类型与方法
3.2 测试工具
3.3 测试环境
4. 测试进度
4.1 里程碑
4.2 时间安排
5. 风险与应对
6. 测试交付物
| 阶段 | 时间 | 交付物 |
|---|
| 需求分析 | 第1周 | 测试计划 |
| 用例设计 | 第2-3周 | 测试用例 |
| 用例评审 | 第3周末 | 评审记录 |
| 测试执行 | 第4-6周 | 缺陷报告 |
| 回归测试 | 第7周 | 回归测试报告 |
| 验收测试 | 第8周 | 验收报告 |
1. 概述
1.1 测试目的
1.2 测试范围
1.3 测试环境
2. 测试结果
2.1 用例执行统计
2.2 缺陷统计
2.3 测试覆盖率
3. 缺陷分析
3.1 缺陷分布
3.2 严重程度分布
3.3 未解决缺陷
4. 测试结论与建议
| 等级 | 说明 | 示例 |
|---|
| 致命 | 系统崩溃、数据丢失 | 支付失败、系统宕机 |
| 严重 | 主要功能不可用 | 无法登录、搜索无结果 |
| 一般 | 次要功能异常 | 排序错误、样式偏移 |
| 轻微 | 界面文字错误、建议性修改 | 拼写错误、对齐不齐 |
| 指标 | 数值 | 百分比 |
|---|
| 总用例数 | 500 | - |
| 通过 | 420 | 84% |
| 失败 | 50 | 10% |
| 阻塞 | 15 | 3% |
| 未执行 | 15 | 3% |
| 缺陷总数 | 65 | - |
| 已修复 | 55 | 84.6% |
| 未修复 | 10 | 15.4% |