黑盒测试(Black Box Testing)

黑盒测试(Black Box Testing)

一句话总结:不关心内部实现,只测试输入和输出是否符合预期。

🌟 快速理解(小白入门)

用生活化类比

就像使用电视遥控器

1
2
3
4
5
6
7
8
9
10
11
12
你使用遥控器时:
- 按"开机"按钮 → 电视打开 ✅
- 按"音量+"按钮 → 音量增大 ✅
- 按"换台"按钮 → 切换频道 ✅

你不需要知道:
❌ 遥控器内部电路如何工作
❌ 电视如何接收信号
❌ 代码如何实现

你只关心:
✅ 按钮按下后,功能是否正常

**黑盒测试就是”只测试功能,不看内部实现”**。


真实场景

测试登录功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
黑盒测试(不看代码):
输入:email = "test@example.com", password = "123456"
预期输出:登录成功,跳转到首页

测试用例:
1. 正确的邮箱和密码 → 登录成功 ✅
2. 错误的密码 → 提示"密码错误" ✅
3. 不存在的邮箱 → 提示"用户不存在" ✅
4. 空密码 → 提示"请输入密码" ✅

不关心:
❌ 密码如何加密
❌ 数据库如何查询
❌ Session 如何管理

📌 核心概念

什么是黑盒测试?

黑盒测试(Black Box Testing):把软件看作一个”黑盒子”,只测试输入和输出,不关心内部实现。

黑盒测试 vs 白盒测试

维度 黑盒测试 白盒测试
关注点 功能 代码
测试者 不需要懂代码 需要懂代码
测试依据 需求文档 代码逻辑
测试范围 用户视角 开发者视角
优势 模拟真实用户 覆盖代码路径

🎯 黑盒测试的优势

优势 1:模拟真实用户 👤

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def test_user_login_black_box():
"""黑盒测试:用户登录"""
# 不关心内部实现,只测试功能

# 测试用例 1:正确的凭据
response = login(email="test@example.com", password="password123")
assert response["success"] == True
assert "token" in response

# 测试用例 2:错误的密码
response = login(email="test@example.com", password="wrong")
assert response["success"] == False
assert response["error"] == "密码错误"

# 测试用例 3:不存在的用户
response = login(email="notexist@example.com", password="password123")
assert response["success"] == False
assert response["error"] == "用户不存在"

优势 2:独立于实现 🔓

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 即使内部实现改变,黑盒测试仍然有效

# 实现 V1:使用 MD5 加密
def login_v1(email, password):
hashed = md5(password)
user = db.query(f"SELECT * FROM users WHERE email='{email}' AND password='{hashed}'")
return {"success": user is not None}

# 实现 V2:使用 bcrypt 加密
def login_v2(email, password):
user = db.query(f"SELECT * FROM users WHERE email='{email}'")
if user and bcrypt.verify(password, user.password):
return {"success": True}
return {"success": False}

# 黑盒测试对两个版本都有效
def test_login_black_box():
response = login(email="test@example.com", password="password123")
assert response["success"] == True

🔄 黑盒测试技术

1. 等价类划分

定义:将输入分为有效类和无效类。

示例

1
2
3
4
5
6
7
8
9
10
11
12
# 测试年龄输入(有效范围:18-65)
def test_age_input():
# 有效等价类
assert validate_age(18) == True # 最小值
assert validate_age(40) == True # 中间值
assert validate_age(65) == True # 最大值

# 无效等价类
assert validate_age(17) == False # 小于最小值
assert validate_age(66) == False # 大于最大值
assert validate_age(-1) == False # 负数
assert validate_age(0) == False # 零

2. 边界值分析

定义:测试边界值和边界附近的值。

示例

1
2
3
4
5
6
7
8
9
10
11
# 测试年龄输入(有效范围:18-65)
def test_age_boundary():
# 下边界
assert validate_age(17) == False # 边界外
assert validate_age(18) == True # 边界上
assert validate_age(19) == True # 边界内

# 上边界
assert validate_age(64) == True # 边界内
assert validate_age(65) == True # 边界上
assert validate_age(66) == False # 边界外

3. 决策表测试

定义:使用决策表覆盖所有组合。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 测试折扣计算
# 规则:会员 + 满100元 = 9折
# 会员 + 不满100元 = 95折
# 非会员 + 满100元 = 95折
# 非会员 + 不满100元 = 无折扣

def test_discount_decision_table():
# 会员 + 满100元
assert calculate_discount(is_member=True, amount=100) == 0.9

# 会员 + 不满100元
assert calculate_discount(is_member=True, amount=50) == 0.95

# 非会员 + 满100元
assert calculate_discount(is_member=False, amount=100) == 0.95

# 非会员 + 不满100元
assert calculate_discount(is_member=False, amount=50) == 1.0

4. 状态转换测试

定义:测试状态之间的转换。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 测试订单状态转换
def test_order_state_transition():
order = Order()

# 初始状态
assert order.status == "pending"

# pending → paid
order.pay()
assert order.status == "paid"

# paid → shipped
order.ship()
assert order.status == "shipped"

# shipped → delivered
order.deliver()
assert order.status == "delivered"

# 无效转换
with pytest.raises(InvalidStateTransition):
order.pay() # 已支付,不能再支付

📊 最佳实践

1. 基于需求编写测试 📝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 需求:用户登录功能
# - 支持邮箱和密码登录
# - 密码错误提示"密码错误"
# - 用户不存在提示"用户不存在"
# - 登录成功返回 token

def test_login_requirements():
"""基于需求的黑盒测试"""
# 需求 1:支持邮箱和密码登录
response = login(email="test@example.com", password="password123")
assert "token" in response

# 需求 2:密码错误提示
response = login(email="test@example.com", password="wrong")
assert response["error"] == "密码错误"

# 需求 3:用户不存在提示
response = login(email="notexist@example.com", password="password123")
assert response["error"] == "用户不存在"

2. 覆盖所有场景 ✅

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@pytest.mark.parametrize("email,password,expected", [
# 正常场景
("test@example.com", "password123", {"success": True}),

# 异常场景
("test@example.com", "wrong", {"success": False, "error": "密码错误"}),
("notexist@example.com", "password123", {"success": False, "error": "用户不存在"}),
("", "password123", {"success": False, "error": "请输入邮箱"}),
("test@example.com", "", {"success": False, "error": "请输入密码"}),

# 边界场景
("a@b.c", "123456", {"success": True}), # 最短邮箱
("test@example.com", "a" * 100, {"success": False}), # 超长密码
])
def test_login_all_scenarios(email, password, expected):
response = login(email=email, password=password)
assert response == expected

3. 使用测试工具 🛠️

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 使用 Pytest 进行黑盒测试
import pytest
import requests

BASE_URL = "https://api.example.com"

class TestUserAPI:
"""用户 API 黑盒测试"""

def test_register(self):
"""测试用户注册"""
response = requests.post(f"{BASE_URL}/register", json={
"email": "newuser@example.com",
"password": "password123"
})
assert response.status_code == 201
assert "user_id" in response.json()

def test_login(self):
"""测试用户登录"""
response = requests.post(f"{BASE_URL}/login", json={
"email": "test@example.com",
"password": "password123"
})
assert response.status_code == 200
assert "token" in response.json()

def test_get_profile(self):
"""测试获取用户信息"""
# 先登录
login_response = requests.post(f"{BASE_URL}/login", json={
"email": "test@example.com",
"password": "password123"
})
token = login_response.json()["token"]

# 获取用户信息
response = requests.get(
f"{BASE_URL}/profile",
headers={"Authorization": f"Bearer {token}"}
)
assert response.status_code == 200
assert "email" in response.json()

🎓 学习资源

书籍推荐

  • 《软件测试的艺术》- Glenford Myers
  • 《Google 软件测试之道》- James Whittaker

官方文档


🔗 相关主题

  • [[白盒测试]] - 关注内部实现的测试
  • [[单元测试]] - 通常是白盒测试
  • [[系统测试]] - 通常是黑盒测试

💡 快速参考卡片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
黑盒测试速查表
================

定义:只测试输入输出,不关心内部实现

核心特征:
🎯 关注功能
👤 模拟真实用户
🔓 独立于实现
📝 基于需求

测试技术:
1. 等价类划分
2. 边界值分析
3. 决策表测试
4. 状态转换测试

黑盒 vs 白盒:
- 黑盒:测试功能(用户视角)
- 白盒:测试代码(开发者视角)

最佳实践:
1. 基于需求编写测试
2. 覆盖所有场景
3. 使用测试工具
4. 自动化执行

推荐工具:
- Python: Pytest
- JavaScript: Jest
- API: Postman

适用场景:
✅ 功能测试
✅ 系统测试
✅ 验收测试
✅ 回归测试