实验一 黑盒测试
实验一 黑盒测试
一、实验目的
1、 掌握黑盒测试的基础知识;
2、 掌握黑盒测试的检查内容及测试目的;
3、 掌握黑盒测试的几种基本测试方法:等价类划分方法、边界值分析方法、因果图法和决策表法;
二、实验要求
1、 复习有关内容,理解黑盒测试;
2、 掌握等价类划分、边界值分析方法、因果图法和决策表法,并能设计出测试用例;
3、 对具体软件,能分别使用相应的黑盒测试方法设计测试用例,并实施测试、分析测试结果。
三、实验内容
1、设计函数实现输入日期显示星期几,并用等价类及边界值法测试
实验步骤:
① 设计程序
from flask import Flask, render_template, request
from datetime import datetime
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def index():
result = None
test_cases = []
test_results = []
# 如果是POST请求,处理表单提交
if request.method == 'POST':
date_str = request.form.get('date')
# 尝试解析日期
try:
date_obj = datetime.strptime(date_str, '%Y-%m-%d')
# 获取星期几(0-6对应周一到周日)
weekday = date_obj.weekday()
# 转换为中文星期表示
weekdays = ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"]
result = weekdays[weekday]
# 生成测试用例(等价类划分法)
test_cases = [
{"id": "TC1", "input": "2023-10-05", "expected": "星期四"},
{"id": "TC2", "input": "2023-02-28", "expected": "星期二"},
{"id": "TC3", "input": "2020-02-29", "expected": "星期六"},
{"id": "TC4", "input": "2023-04-31", "expected": "无效日期"},
{"id": "TC5", "input": "2023/10/05", "expected": "日期格式错误"},
{"id": "TC6", "input": "2023-13-01", "expected": "月份超出范围"}
]
# 执行测试用例
test_results = []
for case in test_cases:
try:
test_date = datetime.strptime(case["input"], '%Y-%m-%d')
test_weekday = test_date.weekday()
actual = weekdays[test_weekday]
status = "通过" if actual == case["expected"] else "失败"
except ValueError:
actual = "无效日期"
status = "通过" if actual == case["expected"] else "失败"
except Exception:
actual = "日期格式错误"
status = "通过" if actual == case["expected"] else "失败"
test_results.append({
"id": case["id"],
"input": case["input"],
"expected": case["expected"],
"actual": actual,
"status": status
})
except ValueError:
result = "无效日期"
except Exception:
result = "日期格式错误"
return render_template('index.html', result=result, test_cases=test_cases, test_results=test_results)
if __name__ == '__main__':
app.run(debug=True)
Index.Html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>日期星期查询</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.container {
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
}
.form-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input[type="text"] {
width: 100%;
padding: 8px;
box-sizing: border-box;
}
button {
background-color: #4CAF50;
color: white;
padding: 10px 15px;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #45a049;
}
.result {
margin-top: 20px;
padding: 15px;
background-color: #e9f7ef;
border-radius: 4px;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
.pass {
color: green;
font-weight: bold;
}
.fail {
color: red;
font-weight: bold;
}
</style>
</head>
<body>
<div class="container">
<h1>日期星期查询</h1>
<form method="post">
<div class="form-group">
<label for="date">请输入日期 (格式: YYYY-MM-DD):</label>
<input type="text" id="date" name="date" required>
</div>
<button type="submit">查询星期</button>
</form>
{% if result %}
<div class="result">
<h3>查询结果:</h3>
<p>{{ result }}</p>
</div>
{% endif %}
<h2>等价类划分法测试用例</h2>
{% if test_results %}
<table>
<thead>
<tr>
<th>测试用例ID</th>
<th>输入日期</th>
<th>预期输出</th>
<th>实际输出</th>
<th>测试结果</th>
</tr>
</thead>
<tbody>
{% for case in test_results %}
<tr>
<td>{{ case.id }}</td>
<td>{{ case.input }}</td>
<td>{{ case.expected }}</td>
<td>{{ case.actual }}</td>
<td class="{% if case.status == '通过' %}pass{% else %}fail{% endif %}">{{ case.status }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>暂无测试结果</p>
{% endif %}
</div>
</body>
</html>
② 划分等价类,得到等价类表。等价类表格式如下:
|
输入条件 |
有效等价类 |
唯一标识 |
无效等价类 |
唯一标识 |
|
年 |
1900到2050内的闰年 |
(1) |
Year<1900 |
(10) |
|
|
1900到2050内的平年 |
(2) |
Year>2050 |
(11) |
|
|
|
|
非数字 |
(12) |
|
月 |
1,3,5,7,8,10,12 |
(3) |
Mouth<1 |
(13) |
|
|
4,6,9,11 |
(4) |
Mouth>12 |
(14) |
|
|
2 |
(5) |
非数字 |
(15) |
|
日 |
1~28 |
(6) |
Day<1 |
(16) |
|
|
29 |
(7) |
Day>31 |
(17) |
|
|
30 |
(8) |
Year为闰年且Mouth为2时,Day>29 |
(18) |
|
|
31 |
(9) |
Year为平年且Mouth为2时,Day>28 |
(19) |
|
|
|
() |
Mouth=1,3,5,7,8,10,12时,Day>31 |
(20) |
|
|
|
() |
Mouth=4,6,9,11时,Day>30 |
(21) |
|
|
|
|
非数字 |
(22) |
③ 运用等价类划分法设计测试用例,得到测试用例表。测试用例表格式如下:/-/*
|
序号 |
输入数据 |
覆盖等价类 |
输出 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
④ 运用边界值法设计测试用例。
2、找零钱最佳组合
假设商店货品价格(R) 都不大于100元(且为整数),若顾客付款(P)在100元内,现有一个程序能在每位顾客付款后给出找零钱的最佳组合(找给顾客货币张数最少)。 假定此商店的货币面值只包括:50元(N50)、10元(N10)、 5元(N5)、1元(N1) 四种。
请结合等价类划分法和边界值分析法为上述程序设计 出相应的测试用例。
实验步骤:
同上题
- 设计程序
change_calculator.py
from flask import Flask, render_template, request
app = Flask(__name__)
class ChangeCalculator:
@staticmethod
def find_change(price, payment):
if payment < price:
return None, "付款不足"
if price < 0 or payment < 0:
return None, "价格和付款不能为负数"
if price > 100 or payment > 100:
return None, "价格和付款不能超过100元"
change = payment - price
if change == 0:
return {"N50": 0, "N10": 0, "N5": 0, "N1": 0}, "无需找零"
denominations = [50, 10, 5, 1]
counts = {"N50": 0, "N10": 0, "N5": 0, "N1": 0}
for denom in denominations:
count = change // denom
counts[f"N{denom}"] = count
change %= denom
return counts, f"找零: {payment - price}元"
@app.route('/', methods=['GET', 'POST'])
def index():
result = None
message = ""
test_cases = []
test_results = []
# 等价类划分测试用例
equivalence_test_cases = [
{"id": "EC1", "price": 10, "payment": 10, "expected": {"N50": 0, "N10": 0, "N5": 0, "N1": 0},
"expected_msg": "无需找零"},
{"id": "EC2", "price": 5, "payment": 15, "expected": {"N50": 0, "N10": 1, "N5": 0, "N1": 0},
"expected_msg": "找零: 10元"},
{"id": "EC3", "price": 20, "payment": 10, "expected": None, "expected_msg": "付款不足"},
{"id": "EC4", "price": 0, "payment": 5, "expected": None, "expected_msg": "付款不足"},
{"id": "EC5", "price": 10, "payment": 0, "expected": None, "expected_msg": "价格和付款不能为负数"},
{"id": "EC6", "price": 150, "payment": 200, "expected": None, "expected_msg": "价格和付款不能超过100元"},
{"id": "EC7", "price": 50, "payment": 200, "expected": None, "expected_msg": "价格和付款不能超过100元"}
]
# 边界值测试用例
boundary_test_cases = [
{"id": "BV1", "price": 0, "payment": 5, "expected": None, "expected_msg": "付款不足"},
{"id": "BV2", "price": 100, "payment": 200, "expected": {"N50": 2, "N10": 0, "N5": 0, "N1": 0},
"expected_msg": "找零: 100元"},
{"id": "BV3", "price": 5, "payment": 10, "expected": {"N50": 0, "N10": 1, "N5": 0, "N1": 0},
"expected_msg": "找零: 5元"},
{"id": "BV4", "price": 1, "payment": 2, "expected": {"N50": 0, "N10": 0, "N5": 0, "N1": 1},
"expected_msg": "找零: 1元"},
{"id": "BV5", "price": 10, "payment": 20, "expected": {"N50": 0, "N10": 1, "N5": 0, "N1": 0},
"expected_msg": "找零: 10元"},
{"id": "BV6", "price": 50, "payment": 100, "expected": {"N50": 1, "N10": 0, "N5": 0, "N1": 0},
"expected_msg": "找零: 50元"},
{"id": "BV7", "price": 99, "payment": 100, "expected": {"N50": 0, "N10": 0, "N5": 0, "N1": 1},
"expected_msg": "找零: 1元"},
{"id": "BV8", "price": 1, "payment": 100, "expected": {"N50": 1, "N10": 5, "N5": 0, "N1": 0},
"expected_msg": "找零: 99元"}
]
# 合并测试用例
test_cases = equivalence_test_cases + boundary_test_cases
# 执行测试用例
for case in test_cases:
calculator = ChangeCalculator()
result_dict, msg = calculator.find_change(case["price"], case["payment"])
if result_dict == case["expected"] and msg == case["expected_msg"]:
status = "通过"
else:
status = "失败"
test_results.append({
"id": case["id"],
"price": case["price"],
"payment": case["payment"],
"expected": case["expected"],
"expected_msg": case["expected_msg"],
"actual": result_dict,
"actual_msg": msg,
"status": status
})
# 处理表单提交
if request.method == 'POST':
price = int(request.form.get('price', 0))
payment = int(request.form.get('payment', 0))
calculator = ChangeCalculator()
result, message = calculator.find_change(price, payment)
return render_template('change_calculator.html', result=result, message=message, test_results=test_results)
if __name__ == '__main__':
app.run(debug=True)
change_calculator.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>找零钱最佳组合</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.container {
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
}
.form-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input[type="number"] {
width: 100%;
padding: 8px;
box-sizing: border-box;
}
button {
background-color: #4CAF50;
color: white;
padding: 10px 15px;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #45a049;
}
.result {
margin-top: 20px;
padding: 15px;
background-color: #e9f7ef;
border-radius: 4px;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
.pass {
color: green;
font-weight: bold;
}
.fail {
color: red;
font-weight: bold;
}
</style>
</head>
<body>
<div class="container">
<h1>找零钱最佳组合</h1>
<form method="post">
<div class="form-group">
<label for="price">商品价格 (元):</label>
<input type="number" id="price" name="price" min="0" max="100" required>
</div>
<div class="form-group">
<label for="payment">顾客付款 (元):</label>
<input type="number" id="payment" name="payment" min="0" max="100" required>
</div>
<button type="submit">计算找零</button>
</form>
{% if message %}
<div class="result">
<h3>结果:</h3>
<p>{{ message }}</p>
{% if result %}
<p>50元: {{ result.N50 }}张</p>
<p>10元: {{ result.N10 }}张</p>
<p>5元: {{ result.N5 }}张</p>
<p>1元: {{ result.N1 }}张</p>
{% endif %}
</div>
{% endif %}
<h2>测试用例结果</h2>
<table>
<thead>
<tr>
<th>测试用例ID</th>
<th>价格</th>
<th>付款</th>
<th>预期结果</th>
<th>实际结果</th>
<th>测试结果</th>
</tr>
</thead>
<tbody>
{% for case in test_results %}
<tr>
<td>{{ case.id }}</td>
<td>{{ case.price }}元</td>
<td>{{ case.payment }}元</td>
<td>
{% if case.expected %}
{% if case.expected_msg %}{{ case.expected_msg }}{% else %}
50元: {{ case.expected.N50 }}张,
10元: {{ case.expected.N10 }}张,
5元: {{ case.expected.N5 }}张,
1元: {{ case.expected.N1 }}张
{% endif %}
{% else %}
{{ case.expected_msg }}
{% endif %}
</td>
<td>
{% if case.actual %}
{% if case.actual_msg %}{{ case.actual_msg }}{% else %}
50元: {{ case.actual.N50 }}张,
10元: {{ case.actual.N10 }}张,
5元: {{ case.actual.N5 }}张,
1元: {{ case.actual.N1 }}张
{% endif %}
{% else %}
{{ case.actual_msg }}
{% endif %}
</td>
<td class="{% if case.status == '通过' %}pass{% else %}fail{% endif %}">{{ case.status }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</body>
</html>
2.等价类划分
等价类表如下:
|
等价类编号 |
输入条件 |
有效/无效 |
描述 |
|
EC1 |
付款等于价格 |
有效 |
找零为0 |
|
EC2 |
付款大于价格 |
有效 |
正常找零 |
|
EC3 |
付款小于价格 |
无效 |
付款不足 |
|
EC4 |
价格为0 |
无效 |
无效价格 |
|
EC5 |
付款为0 |
无效 |
未付款 |
|
EC6 |
价格大于100 |
无效 |
价格超出范围 |
|
EC7 |
付款大于100 |
无效 |
付款超出范围 |
|
EC8 |
正常找零边界值 |
有效 |
找零为1元、5元、10元、50元等边界情况 |
3. 边界值分析
边界值测试用例:
|
测试用例ID |
价格(R) |
付款(P) |
预期输出 |
边界情况 |
|
BV1 |
0 |
5 |
付款不足 |
价格最小值 |
|
BV2 |
100 |
200 |
50元:2张 |
价格最大值 |
|
BV3 |
5 |
10 |
5元:1张 |
找零为5元 |
|
BV4 |
1 |
2 |
1元:1张 |
找零为1元 |
|
BV5 |
10 |
20 |
10元:1张 |
找零为10元 |
|
BV6 |
50 |
100 |
50元:1张 |
找零为50元 |
|
BV7 |
99 |
100 |
1元:1张 |
找零最小非零 |
|
BV8 |
1 |
100 |
50元:1张, 10元:5张 |
找零最大值 |
测试用例结果
3、有一个饮料自动售货机(处理单价为5角钱)的控制处理软件,它的软件规格说明如下:
若投入5角钱的硬币,按下“橙汁”或“啤酒”的按钮,则相应的饮料就送出来。若投入1元钱的硬币,同样也是按“橙汁”或“啤酒”的按钮,则自动售货机在送出相应饮料的同时退回5角钱的硬币。
模拟程序如下:
用因果图法测试该程序,并撰写实验报告。
实验步骤:
①编写程序
vending_machine.py
from flask import Flask, render_template, request
app = Flask(__name__)
class VendingMachine:
def __init__(self):
self.coins = []
self.selection = None
def insert_coin(self, coin):
self.coins.append(coin)
def select_product(self, product):
self.selection = product
def dispense(self):
if not self.selection:
return "请选择商品"
total = sum(self.coins)
if self.selection == "orange" and total >= 0.5:
change = total - 0.5
self.coins = []
self.selection = None
return f"橙汁已送出。找零:{change}元"
elif self.selection == "beer" and total >= 0.5:
change = total - 0.5
self.coins = []
self.selection = None
return f"啤酒已送出。找零:{change}元"
else:
return "金额不足"
@app.route('/', methods=['GET', 'POST'])
def index():
result = ""
vending_machine = VendingMachine()
if request.method == 'POST':
coin = request.form.get('coin')
product = request.form.get('product')
if coin:
vending_machine.insert_coin(float(coin))
if product:
vending_machine.select_product(product)
result = vending_machine.dispense()
return render_template('vending_machine.html', result=result)
if __name__ == '__main__':
app.run(debug=True)
vending_machine.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>自动售货机</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.container {
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
}
.form-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input[type="radio"] {
margin-right: 10px;
}
button {
background-color: #4CAF50;
color: white;
padding: 10px 15px;
border: none;
border-radius: 4px;
cursor: pointer;
margin-right: 10px;
}
button:hover {
background-color: #45a049;
}
.result {
margin-top: 20px;
padding: 15px;
background-color: #e9f7ef;
border-radius: 4px;
}
</style>
</head>
<body>
<div class="container">
<h1>自动售货机</h1>
<form method="post">
<div class="form-group">
<label>请投币:</label>
<input type="radio" id="coin_1" name="coin" value="1.0">
<label for="coin_1">1元</label>
<input type="radio" id="coin_0.5" name="coin" value="0.5">
<label for="coin_0.5">5角</label>
</div>
<div class="form-group">
<label>请选择商品:</label>
<input type="radio" id="product_orange" name="product" value="orange">
<label for="product_orange">橙汁</label>
<input type="radio" id="product_beer" name="product" value="beer">
<label for="product_beer">啤酒</label>
</div>
<button type="submit" name="action" value="dispense">确定</button>
<button type="submit" name="action" value="reset">复位</button>
</form>
{% if result %}
<div class="result">
<h3>结果:</h3>
<p>{{ result }}</p>
</div>
{% endif %}
</div>
</body>
</html>
②分析原因与结果
原因:
投入5角钱(C1)
投入1元钱(C2)
选择橙汁(C3)
选择啤酒(C4)
结果:
送出橙汁(E1)
送出啤酒(E2)
找零5角钱(E3)
③画出因果图
④转化为决策表
|
投入5角 (C1) |
投入1元 (C2) |
选择橙汁 (C3) |
选择啤酒 (C4) |
送出橙汁 (E1) |
送出啤酒 (E2) |
找零5角 (E3) |
|
T |
F |
T |
F |
T |
F |
F |
|
T |
F |
F |
T |
F |
T |
F |
|
F |
T |
T |
F |
T |
F |
T |
|
F |
T |
F |
T |
F |
T |
T |
|
T |
F |
T |
T |
T |
T |
F |
|
F |
T |
T |
T |
T |
T |
T |
⑤根据决策表设计测试用例,得到测试用例表
|
测试用例ID |
投入5角 (C1) |
投入1元 (C2) |
选择橙汁 (C3) |
选择啤酒 (C4) |
预期结果 |
|
TC1 |
T |
F |
T |
F |
送出橙汁,不找零 |
|
TC2 |
T |
F |
F |
T |
送出啤酒,不找零 |
|
TC3 |
F |
T |
T |
F |
送出橙汁,找零5角 |
|
TC4 |
F |
T |
F |
T |
送出啤酒,找零5角 |
|
TC5 |
T |
F |
T |
T |
送出橙汁和啤酒,不找零 |
|
TC6 |
F |
T |
T |
T |
送出橙汁和啤酒,找零5角 |
4、航空服务查询问题:根据航线,仓位,飞行时间查询航空服务。
假设一个中国的航空公司规定:
① 中国去欧美的航线所有座位都有食物供应,每个座位都可以播放电影。
② 中国去非欧美的国外航线都有食物供应,只有商务仓可以播放电影。
③ 中国国内的航班的商务仓有食物供应,但是不可以播放电影
④ 中国国内航班的经济仓只有当飞行时间大于2小时时才有食物供应,但是不可以播放电影。
请用程序实现上述功能,并用决策表法设计测试用例,再执行测试,撰写实验报告。
实验步骤:
① 编写程序
flight_services.py
from flask import Flask, render_template, request
app = Flask(__name__)
class FlightServiceChecker:
def check_services(self, route, cabin, duration):
food = False
movie = False
if route == "欧美":
food = True
movie = True
elif route == "国外非欧美":
food = True
if cabin == "商务舱":
movie = True
elif route == "国内":
if cabin == "商务舱":
food = True
elif cabin == "经济舱":
if duration == "超过两小时":
food = True
return food, movie
@app.route('/', methods=['GET', 'POST'])
def index():
result = None
food = None
movie = None
if request.method == 'POST':
route = request.form.get('route')
cabin = request.form.get('cabin')
duration = request.form.get('duration')
checker = FlightServiceChecker()
food, movie = checker.check_services(route, cabin, duration)
result = {
"route": route,
"cabin": cabin,
"duration": duration,
"food": "是" if food else "否",
"movie": "是" if movie else "否"
}
return render_template('flight_services.html', result=result)
if __name__ == '__main__':
app.run(debug=True)
flight_services.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>航空服务查询</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.container {
background-color: #f5f5f5;
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
}
.form-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input[type="radio"] {
margin-right: 10px;
}
button {
background-color: #4CAF50;
color: white;
padding: 10px 15px;
border: none;
border-radius: 4px;
cursor: pointer;
margin-right: 10px;
}
button:hover {
background-color: #45a049;
}
.result {
margin-top: 20px;
padding: 15px;
background-color: #e9f7ef;
border-radius: 4px;
}
</style>
</head>
<body>
<div class="container">
<h1>航空服务查询</h1>
<form method="post">
<div class="form-group">
<label>航线:</label>
<input type="radio" id="route1" name="route" value="欧美">
<label for="route1">欧美</label>
<input type="radio" id="route2" name="route" value="国外非欧美">
<label for="route2">国外非欧美</label>
<input type="radio" id="route3" name="route" value="国内">
<label for="route3">国内</label>
</div>
<div class="form-group">
<label>舱位:</label>
<input type="radio" id="cabin1" name="cabin" value="商务舱">
<label for="cabin1">商务舱</label>
<input type="radio" id="cabin2" name="cabin" value="经济舱">
<label for="cabin2">经济舱</label>
</div>
<div class="form-group">
<label>飞行时间:</label>
<input type="radio" id="duration1" name="duration" value="两小时以内">
<label for="duration1">两小时以内</label>
<input type="radio" id="duration2" name="duration" value="超过两小时">
<label for="duration2">超过两小时</label>
</div>
<button type="submit" name="action" value="query">查询</button>
<button type="submit" name="action" value="exit">退出</button>
</form>
{% if result %}
<div class="result">
<h3>查询结果:</h3>
<p>航线:{{ result.route }}</p>
<p>舱位:{{ result.cabin }}</p>
<p>飞行时间:{{ result.duration }}</p>
<p>食物供应:{{ result.food }}</p>
<p>播放电影:{{ result.movie }}</p>
</div>
{% endif %}
</div>
</body>
</html>
② 构造决策表
|
航线 (C1) |
舱位 (C2) |
飞行时间 (C3) |
食物供应 (E1) |
播放电影 (E2) |
|
欧美 |
商务舱 |
两小时以内 |
是 |
是 |
|
欧美 |
商务舱 |
超过两小时 |
是 |
是 |
|
欧美 |
经济舱 |
两小时以内 |
是 |
是 |
|
欧美 |
经济舱 |
超过两小时 |
是 |
是 |
|
国外非欧美 |
商务舱 |
两小时以内 |
是 |
是 |
|
国外非欧美 |
商务舱 |
超过两小时 |
是 |
是 |
|
国外非欧美 |
经济舱 |
两小时以内 |
是 |
否 |
|
国外非欧美 |
经济舱 |
超过两小时 |
是 |
否 |
|
国内 |
商务舱 |
两小时以内 |
是 |
否 |
|
国内 |
商务舱 |
超过两小时 |
是 |
否 |
|
国内 |
经济舱 |
两小时以内 |
否 |
否 |
|
国内 |
经济舱 |
超过两小时 |
是 |
否 |
③ 根据决策表设计测试用例,得到测试用例表
表格
复制
|
测试用例ID |
航线 (C1) |
舱位 (C2) |
飞行时间 (C3) |
预期结果 |
|
TC1 |
欧美 |
商务舱 |
两小时以内 |
食物供应:是,播放电影:是 |
|
TC2 |
欧美 |
经济舱 |
两小时以内 |
食物供应:是,播放电影:是 |
|
TC3 |
国外非欧美 |
商务舱 |
两小时以内 |
食物供应:是,播放电影:是 |
|
TC4 |
国外非欧美 |
经济舱 |
两小时以内 |
食物供应:是,播放电影:否 |
|
TC5 |
国内 |
商务舱 |
两小时以内 |
食物供应:是,播放电影:否 |
|
TC6 |
国内 |
经济舱 |
两小时以内 |
食物供应:否,播放电影:否 |
|
TC7 |
国内 |
经济舱 |
超过两小时 |
食物供应:是,播放电影:否 |
5、旅馆住宿系统中,旅馆业主可进行添加房间操作。
– 旅馆业主登录旅馆住宿系统后,可以请求添加房间;
– 待进入“房间管理”对话框,单击“添加”按钮可进行添加房间操作;
– 添加房间时,可以设定房间的房间编号、房间类型、房间描述信息;
– 添加房间信息不能缺失,若某一项未填写,要给出提示信息;
– 房间编号长度不超过5个字符;
– 房间描述长度不超过1000个字符;
– 房间信息不能重复,成功填写后,可进行保存或取消操作,之后返回“房间管理”对话框,结束添加房间流程。
实验步骤:
利用黑盒测试策略编写添加房间功能的测试用例。
设计程序
add_room。Py
from flask import Flask, render_template, request, redirect, url_for, flash
app = Flask(__name__)
app.secret_key = 'your_secret_key'
# 模拟数据库
rooms = []
class HotelRoomManager:
def add_room(self, room_number, room_type, room_description):
# 验证房间编号长度
if len(room_number) > 5:
return False, "房间编号长度不能超过5个字符"
# 验证房间描述长度
if len(room_description) > 1000:
return False, "房间描述长度不能超过1000个字符"
# 验证房间信息是否重复
for room in rooms:
if room['room_number'] == room_number:
return False, "房间信息已存在"
# 添加房间
rooms.append({
'room_number': room_number,
'room_type': room_type,
'room_description': room_description
})
return True, "房间添加成功"
@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
room_number = request.form.get('room_number')
room_type = request.form.get('room_type')
room_description = request.form.get('room_description')
if not room_number or not room_type or not room_description:
flash("房间信息不能缺失")
return redirect(url_for('index'))
manager = HotelRoomManager()
success, message = manager.add_room(room_number, room_type, room_description)
if success:
flash(message)
return redirect(url_for('room_management'))
else:
flash(message)
return render_template('add_room.html')
@app.route('/room_management')
def room_management():
return render_template('room_management.html', rooms=rooms)
if __name__ == '__main__':
app.run(debug=True)
add_room.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>添加房间</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.container {
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
}
.form-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input[type="text"], textarea {
width: 100%;
padding: 8px;
box-sizing: border-box;
}
button {
background-color: #4CAF50;
color: white;
padding: 10px 15px;
border: none;
border-radius: 4px;
cursor: pointer;
margin-right: 10px;
}
button:hover {
background-color: #45a049;
}
.message {
color: red;
margin-top: 10px;
}
</style>
</head>
<body>
<div class="container">
<h1>添加房间</h1>
<form method="post">
<div class="form-group">
<label for="room_number">房间编号:</label>
<input type="text" id="room_number" name="room_number" required>
</div>
<div class="form-group">
<label for="room_type">房间类型:</label>
<input type="text" id="room_type" name="room_type" required>
</div>
<div class="form-group">
<label for="room_description">房间描述:</label>
<textarea id="room_description" name="room_description" required></textarea>
</div>
<button type="submit">保存</button>
<button type="reset">取消</button>
</form>
{% with messages = get_flashed_messages() %}
{% if messages %}
<div class="message">
{% for message in messages %}
<p>{{ message }}</p>
{% endfor %}
</div>
{% endif %}
{% endwith %}
</div>
</body>
</html>
room_management.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>房间管理</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.container {
padding: 20px;
border-radius: 8px;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
button {
background-color: #4CAF50;
color: white;
padding: 10px 15px;
border: none;
border-radius: 4px;
cursor: pointer;
margin-right: 10px;
}
button:hover {
background-color: #45a049;
}
</style>
</head>
<body>
<div class="container">
<h1>房间管理</h1>
<table>
<thead>
<tr>
<th>房间编号</th>
<th>房间类型</th>
<th>房间描述</th>
</tr>
</thead>
<tbody>
{% for room in rooms %}
<tr>
<td>{{ room.room_number }}</td>
<td>{{ room.room_type }}</td>
<td>{{ room.room_description }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<br>
<a href="{{ url_for('index') }}">
<button>添加房间</button>
</a>
</div>
</body>
</html>
测试用例
|
测试用例ID |
房间编号 |
房间类型 |
房间描述 |
预期结果 |
|
TC1 |
123 |
标准间 |
舒适的标准间 |
添加成功 |
|
TC2 |
12345 |
豪华间 |
豪华的房间 |
添加成功 |
|
TC3 |
123456 |
豪华间 |
豪华的房间 |
房间编号过长 |
|
TC4 |
123 |
标准间 |
舒适的标准间(超过1000字符) |
房间描述过长 |
|
TC5 |
123 |
标准间 |
舒适的标准间 |
房间信息重复 |
|
TC6 |
123 |
|
舒适的标准间 |
房间类型缺失 |
|
TC7 |
|
标准间 |
舒适的标准间 |
房间编号缺失 |
四、实验思考
① 在实际的测试中,如何设计测试用例才能达到用最少的测试用例检测出最多的缺陷;
1. 基于风险设计测试用例
识别高风险模块:根据软件的需求规格说明书和设计文档,识别出高风险模块。例如,在一个电商系统中,支付模块通常被视为高风险模块,因为它直接关系到交易的安全性和准确性。
优先测试高风险功能:将更多的测试资源和精力投入到高风险模块的测试中,设计更多的测试用例来覆盖这些模块的各种输入和场景。
2. 使用等价类划分和边界值分析
等价类划分:将输入数据划分为有效的等价类和无效的等价类。例如,对于一个输入框要求输入年龄(1-120岁),有效的等价类是1-120之间的整数,无效的等价类包括小于1、大于120、非整数等。
边界值分析:选择等价类边界附近的值作为测试数据。例如,对于上述年龄输入框,边界值可以是0、1、120、121等。
3. 采用场景测试法
设计业务场景:从业务流程的角度出发,设计测试用例。例如,在一个在线书店系统中,可以设计以下场景:用户搜索书籍、将书籍加入购物车、用户结算、支付成功等。
覆盖关键业务流程:确保每个关键业务流程都有对应的测试用例。
4. 利用错误推测法
基于经验设计测试用例:根据以往的测试经验和常见的软件缺陷类型,设计测试用例。例如,如果之前发现系统在处理大量并发请求时容易出现性能问题,那么在测试时可以设计高并发场景下的测试用例。
② 在进行用例设计时,如何考虑软件测试用例的充分性和减少软件测试用例的冗余性;
1. 确保测试用例的充分性
需求覆盖:确保每个需求都有对应的测试用例。可以使用需求跟踪矩阵来跟踪每个需求对应的测试用例,确保需求的全覆盖。
功能覆盖:对软件的每个功能点都进行测试。例如,对于一个文件编辑软件,要测试打开文件、保存文件、编辑文件等所有功能。
输入覆盖:考虑各种可能的输入情况,包括正常输入、异常输入和边界值输入。例如,对于一个登录功能,要测试正确的用户名和密码、错误的用户名、错误的密码、空用户名等输入情况。
2. 减少测试用例的冗余性
去除重复的测试用例:定期对测试用例进行评审,去除重复的测试用例。例如,如果有多个测试用例都是测试同一个功能的正常输入情况,可以保留一个具有代表性的测试用例,删除其他重复的测试用例。
合并相似的测试用例:将相似的测试用例合并。例如,如果有多个测试用例都是测试不同浏览器下的页面显示问题,可以将它们合并为一个测试用例,使用多个浏览器进行测试。
使用正交数组等设计方法:正交数组是一种统计学方法,可以用于设计测试用例,以减少测试用例的数量,同时保证测试的充分性。通过正交数组,可以在较少的测试用例中覆盖尽可能多的输入组合。

浙公网安备 33010602011771号