系统介绍
碳烤滋味包括 系统管理后台 和 小程序端应用 两部分。其中系统管理后台主要提供给企业内部员工使用,可以对餐厅的分类、菜品、套餐、订单、员工等进行管理维护,对餐厅的各类数据进行统计,并且提供导出报告功能。小程序端主要提供给消费者使用,可以在线浏览菜品、添加购物车、下单、支付、催单等。
(1). 管理端功能
员工登录/退出 , 员工信息管理 , 分类管理 , 菜品管理 , 套餐管理 , 菜品口味管理 , 订单管理 ,数据统计,来单提醒。
(2). 用户端功能
微信登录 , 收件人地址管理 , 用户历史订单查询 , 菜品规格查询 , 购物车功能 , 下单 , 支付、分类及菜品浏览。
界面展示
(1).管理端
图1登录界面
图2工作台界面
图3数据统计界面
图4订单管理界面
图5套餐管理界面
图6菜品管理界面
图7分类管理界面
图8员工管理界面
(2).用户端
图9商品浏览界面
图10购物车界面
图11个人中心界面
图12历史订单界面
功能测试以及非功能测试
提取测试点
图13管理端测试点
图14用户端测试点
部分测试用例
用例标题 | 项目/模块 | 优先级 | 前置条件 | 测试步骤 | 测试数据 | 预期结果 |
登录成功(正确账号+正确密码) | 登录模块 | p0 | 开打登录页面 | 1.输入账号 2.输入密码 | 账号:admin 密码:123456 | 登录成功,跳转到工作台 |
登录成功(账号为空) | 登录模块 | p1 | 开打登录页面 | 1.输入账号 2.输入密码 | 账号: 密码:123456 | 登录失败,提示请输入账号 |
登录成功(未注册账号) | 登录模块 | p1 | 开打登录页面 | 1.输入账号 2.输入密码 | 账号:admin110 密码:123456 | 登录失败,提示账号不存在 |
登录成功(错误密码) | 登录模块 | p1 | 开打登录页面 | 1.输入账号 2.输入密码 | 账号:admin 密码:123456 | 登录失败,提示密码错误 |
展示今日数据,订单管理,菜品总览,套餐总览,订单信息 | 工作台模块 | p2 | 登录成功 | 查看面板 | / | 展示今日数据,订单管理,菜品总览,订单信息 |
工作台数据与数据库数据一致 | 工作台模块 | p2 | 登录成功 | 查看面板 | / | 工作台数据与数据库数据一致 |
工作台数据更新一致性 | 工作台模块 | p2 | 登录成功 用户端下单 | 查看面板 | / | 工作台的订单信息更新,并且有弹窗提示 |
跳转到今日数据 | 工作台模块 | p2 | 登录成功 | 点击详细数据连接 | / | 跳转到今日数据页面 |
跳转到订单管理 | 工作台模块 | p2 | 登录成功 | 点击订单明细连接 | / | 跳转到订单管理 |
跳转到菜品总览 | 工作台模块 | p2 | 登录成功 | 点击菜品总览连接 | / | 跳转到菜品管理 |
跳转到订单管理 | 工作台模块 | p2 | 登录成功 | 点击套餐总览连接 | / | 跳转到套餐管理 |
营业状态更换营业中 | 工作台模块 | p2 | 登录成功 | 点击设置营业状态 | / | 营业状态变成营业中 |
营业状态更换打烊 | 工作台模块 | p3 | 登录成功 | 点击设置营业状态 | / | 营业状态变成打烊 |
跳转到登录页面 | 工作台模块 | p5 | 未登录 | 直接在浏览器输入工作台url | 工作台url | 提示请先登录,强制跳转到登录页面 |
展示营业额统计,用户统计,订单统计,销量排行 | 数据统计模块 | p3 | 登录成功 跳转到数据统计 | 查看面板 | / | 展示正确的营业额统计,用户统计,订单统计,销量排行 |
根据日期更新统计数据(昨日数据) | 数据统计模块 | p3 | 登录成功 跳转到数据统计 | 点击昨日 | / | 正确展示昨日的数据统计 |
根据日期更新统计数据(近7日数据) | 数据统计模块 | p3 | 登录成功 跳转到数据统计 | 点击近7日 | / | 正确展示昨日的数据统计 |
根据日期更新统计数据(近30日数据) | 数据统计模块 | p3 | 登录成功 跳转到数据统计 | 点击近30日 | / | 正确展示近30日的数据统计 |
根据日期更新统计数据(本周数据) | 数据统计模块 | p3 | 登录成功 跳转到数据统计 | 点击本周 | / | 正确展示本周的数据统计 |
根据日期更新统计数据(本月数据) | 数据统计模块 | p3 | 登录成功 跳转到数据统计 | 点击本月 | / | 正确展示本月的统计数据 |
导出excel格式的数据文件 | 数据统计模块 | p3 | 登录成功 跳转到数据统计 | 点击导出按钮 | / | 导出.xlx或者.xlxs的文件,且内容正确 |
跳转到登录页面 | 数据统计模块 | p5 | 未登录 | 直接在浏览器输数据统计页面url | 数据统计页面url | 提示请先登录,强制跳转到登录页面 |
查询订单列表成功(全参查询) | 订单管理模块 | p2 | 登录成功 跳转到订单管理 | 通过搜索栏输入参数查询订单 | 订单号:1718175131837 手机号:13751662345 下单时间:2024.6.12-2024.6.14 订单状态: 已完成 分页参数: 第一页 每页20条 | 查询成功,展示对应订单 |
查询订单列表成功(订单号为空) | 订单管理模块 | p2 | 登录成功 跳转到订单管理 | 通过搜索栏输入参数查询订单 | 订单号: 手机号:13751662345 下单时间:2024.6.12-2024.6.14 订单状态: 已完成 分页参数: 第一页 每页20条 | 查询成功,展示对应订单 |
查询订单列表成功(手机号为空) | 订单管理模块 | p2 | 登录成功 跳转到订单管理 | 通过搜索栏输入参数查询订单 | 订单号:1718175131837 手机号: 下单时间:2024.6.12-2024.6.14 订单状态: 已完成 分页参数: 第一页 每页20条 | 查询成功,展示对应订单 |
查询订单列表成功(时间范围为空) | 订单管理模块 | p2 | 登录成功 跳转到订单管理 | 通过搜索栏输入参数查询订单 | 订单号: 手机号:13751662345 下单时间: 订单状态: 已完成 分页参数: 第一页 每页20条 | 查询成功,展示对应订单 |
查询订单列表成功(订单状态为空) | 订单管理模块 | p2 | 登录成功 跳转到订单管理 | 通过搜索栏输入参数查询订单 | 订单号:1718175131837 手机号:13751662345 下单时间:2024.6.12-2024.6.14 订单状态: 分页参数: 第一页 每页20条 | 查询成功,展示对应订单 |
查询订单列表成功(不存在的订单号) | 订单管理模块 | p2 | 登录成功 跳转到订单管理 | 通过搜索栏输入参数查询订单 | 订单号:1228175131837 手机号:13751662345 下单时间:2024.6.12-2024.6.14 订单状态: 已完成 分页参数: 第一页 每页20条 | 查询成功,但是不展示订单数据 |
查询订单列表成功(不存在的手机号) | 订单管理模块 | p2 | 登录成功 跳转到订单管理 | 通过搜索栏输入参数查询订单 | 订单号:1718175131837 手机号:13751661234 下单时间:2024.6.12-2024.6.14 订单状态: 已完成 分页参数: 第一页 每页20条 | 查询成功,但是不展示订单数据 |
查询订单成功(无效时间范围) | 订单管理模块 | p2 | 登录成功 跳转到订单管理 | 通过搜索栏输入参数查询订单 | 订单号: 手机号:13751662345 下单时间:1999.6.12-1999.6.14 订单状态: 已完成 分页参数: 第一页 每页20条 | 查询成功,展示对应订单列表 |
查询订单列表成功(非自然数页码) | 订单管理模块 | p2 | 登录成功 跳转到订单管理 | 通过搜索栏输入参数查询订单 | 订单号:1718175131837 手机号:13751662345 下单时间:2024.6.12-2024.6.14 订单状态: 已完成 分页参数: 第a页 每页20条 | 系统展示第一页的数据 |
查询订单列表成功(超出范围页码) | 订单管理模块 | p2 | 登录成功 跳转到订单管理 | 通过搜索栏输入参数查询订单 | 订单号: 手机号:13751662345 下单时间:2024.6.12-2024.6.14 订单状态: 已完成 分页参数: 第一页 每页20条 | 查询成功,系统展示最后一页数据 |
查询订单列表成功(订单状态为待接单) | 订单管理模块 | p2 | 登录成功 跳转到订单管理 | 通过搜索栏输入参数查询订单 | 订单号: 手机号: 下单时间: 订单状态: 待接单 分页参数: | 查询成功,系统展示待接单订单列表 |
查询订单列表成功(订单状态为待派送) | 订单管理模块 | p2 | 登录成功 跳转到订单管理 | 通过搜索栏输入参数查询订单 | 订单号: 手机号: 下单时间: 订单状态: 待派送 分页参数: | 查询成功,系统展示待派送订单列表 |
查询订单列表成功(订单状态为派送中) | 订单管理模块 | p2 | 登录成功 跳转到订单管理 | 通过搜索栏输入参数查询订单 | 订单号: 手机号: 下单时间: 订单状态: 派送中 分页参数: | 查询成功,系统展示派送中订单列表 |
查询订单列表成功(订单状态为已完成) | 订单管理模块 | p2 | 登录成功 跳转到订单管理 | 通过搜索栏输入参数查询订单 | 订单号: 手机号: 下单时间: 订单状态: 已完成 分页参数: | 查询成功,系统展示已完成订单列表 |
查询订单列表成功(订单状态为已取消) | 订单管理模块 | p2 | 登录成功 跳转到订单管理 | 通过搜索栏输入参数查询订单 | 订单号: 手机号: 下单时间: 订单状态: 已取消 分页参数: | 查询成功,系统展示已取消订单列表 |
查询订单详情成功 | 订单管理模块 | p2 | 登录成功 跳转到订单管理 | 通过搜索栏输入参数查询订单 | / | 展示订单号,消费者信息,订单的菜品,费用,下单时间 |
订单状态修改成功(待接单修改为待派送) | 订单管理模块 | p2 | 登录成功 跳转到订单管理 | 点击订单列表中的订单的接单 | / | 操作成功(待接单转为待派送) |
订单状态修改成功(待派送修改为派送中) | 订单管理模块 | p2 | 登录成功 跳转到订单管理 | 点击订单列表中的订单的派送 | / | 操作成功(待派送订单转为派送中) |
订单状态修改成功(派送中修改为已完成) | 订单管理模块 | p2 | 登录成功 跳转到订单管理 | 点击订单列表中的订单项完成 | / | 操作成功(派送中订单转为已完成订单) |
订单状态修改成功(待接单修改为已取消) | 订单管理模块 | p2 | 登录成功 跳转到订单管理 | 点击订单列表中的订单项取消 | / | 弹窗要求填写取消原因,选择后提示操作成功,订单状态修改为已取消 |
订单状态修改失败(待派送转为取消) | 订单管理模块 | p2 | 登录成功 跳转到订单管理 | 点击订单列表中的订单项取消 | / | 操作失败,提示请联系顾客 |
订单状态修改失败(派送中转为取消) | 订单管理模块 | p3 | 登录成功 跳转到订单管理 | 点击订单列表中的订单项取消 | / | 操作失败,提示请联系顾客 |
订单状态修改失败(已完成转为取消) | 订单管理模块 | p3 | 登录成功 跳转到订单管理 | 点击订单列表中的订单项取消 | / | 操作失败,提示请联系顾客 |
跳转到登录页面 | 订单管理模块 | p3 | 未登录 | 直接在浏览器输入订单管理页面url | 订单管理页面url | 提示请先登录,强制跳转到登录页面 |
所有订单每天凌晨12点状态更新为已完成 | 订单管理模块 | p1 | / | / | / | 12点后所有订单更新为已完成 |
接口测试
提取测试点
图15管理端接口测试点
图16用户端接口测试点
部分测试用例
login-001 | 登录 | P2 | 登录成功 | 登录 | / | /admin/employee/login | POST | {"content-Type":"application/json"} | json | { "username": "admin", "password": "123456", } | ①响应状态码:200 ②响应数据: { "msg": "", "code": 1, "token": "xxxxxx"} |
login-002 | 登录 | P3 | 登录失败(用户名为空) | 登录 | / | /admin/employee/login | POST | {"content-Type":"application/json"} | json | { "username": "", "password": "123456", } | ①响应状态码:200 ②响应数据: { "msg": "用户名或密码错误", "code": 0} |
login-003 | 登录 | P3 | 登录失败(未注册用户名) | 登录 | / | /admin/employee/login | POST | {"content-Type":"application/json"} | json | { "username": "admin2", "password": "123456", } | ①响应状态码:200 ②响应数据: { "msg": "用户名或密码错误", "code": 0} |
login-004 | 登录 | P3 | 登录失败(密码为空) | 登录 | / | /admin/employee/login | POST | {"content-Type":"application/json"} | json | { "username": "admin2", "password": "", } | ①响应状态码:200 ②响应数据: { "msg": "密码不能为空", "code": 0} |
statistic_001 | 统计 | p3 | 查询成功(正确日期范围) | 用户统计 | 登录成功 | /admin/report/userStatistics | get | {"token":"xxx"} | 字符串 | ?begin=2024-06-10&end=2024-6-15 | ①响应状态码:200 ②响应数据: { "msg": "", "code": 1,data="xxxx"} |
statistic_002 | 统计 | p4 | 查询成功(无日期范围) | 用户统计 | 登录成功 | /admin/report/userStatistics | get | {"token":"xxx"} | 字符串 | / | ①响应状态码:200 ②响应数据: { "msg": "", "code": 1,data="xxxx"} |
statistic_003 | 统计 | p4 | 查询成功(时间范围无效) | 用户统计 | 登录成功 | /admin/report/userStatistics | get | {"token":"xxx"} | 字符串 | ?begin=2024-06-10&end=2024-6-15 | ①响应状态码:200 ②响应数据: { "msg": "", "code": 1,data=""} |
statistic_004 | 统计 | p4 | 查询失败(时间范围格式错误) | 用户统计 | 登录成功 | /admin/report/userStatistics | get | {"token":"xxx"} | 字符串 | ?begin=20240610&end=2024616 | ①响应状态码:200 ②响应数据: { "msg": "时间格式有误", "code": 0,data=""} |
statistic_005 | 统计 | p4 | 查询失败(未登录) | 用户统计 | 未登录 | /admin/report/userStatistics | get | {"token":"xxx"} | 字符串 | ?begin=2024-06-10&end=2024-6-15 | ①响应状态码:401 ②响应数据: { "msg": "请先登录", "code": 0,data=""} |
搭建测试平台
本项目使用pytest作为接口测试框架
一.统一封装请求接口:
1.1.登录接口
# 登录:
import requests
import config
# 创建接口类
class LoginAPI:
# 初始化
def __init__(self):
# 指定url基本信息
self.url_login = config.BASE_URL + "/admin/employee/login"
# 登录
def login(self, test_data):
return requests.post(url=self.url_login, json=test_data)
1.2.统计接口封装
# 登录:
import requests
import config
# 创建接口类
class StatisticAPI:
# 初始化
def __init__(self):
# 指定url基本信息
self.url_statistic_turnover = config.BASE_URL + "/admin/report/turnoverStatistics"
self.url_statistic_user = config.BASE_URL + "/admin/report/userStatistics"
self.url_export = config.BASE_URL + "/admin/shop/export"
# 营业额
def turnoverStatistic(self, test_data,headers):
return requests.get(url=self.url_statistic_turnover,params=test_data,headers=headers)
# 用户
def userStatistic(self, test_data,headers):
return requests.get(url=self.url_statistic_user,data=test_data,headers=headers)
# 导出
def exportExcel(self, headers):
return requests.put(url=self.url_export, headers=headers)
1.3.菜品分页接口
import requests
import config
# 创建接口类
class DishAPI:
# 初始化
def __init__(self):
# 指定url基本信息
self.url_page_search = config.BASE_URL + "/admin/dish/page"
self.url_save = config.BASE_URL + "/admin/dish"
self.url_update = config.BASE_URL + "/admin/dish/"
self.url_update_status = config.BASE_URL + "/admin/dish/status"
# 分页查询
def page_search(self, test_data,headers):
return requests.get(url=self.url_page_search, json=test_data,headers=headers)
# 菜品新增
def dish_save(self,test_data,headers):
return requests.post(url=self.url_save,json=test_data,headers=headers)
# 菜品修改
def dish_update(self,test_data,headers):
return requests.put(url=self.url_update,json=test_data,headers=headers)
# 修改菜品状态信息
def dish_update_status(self,test_data,headers):
return requests.post(url=self.url_update_status,headers=headers)
........
二. 封装工具持久化存储登录时的令牌
import yaml
import config
class YamlUtil:
#读取yaml文件
def read_extract_yaml(self,key):
with open(config.BASE_PATH+'/extract.yml',mode='r',encoding='utf-8') as f:
value = yaml.load(stream=f,Loader=yaml.FullLoader)
return value[key]
#写入yaml文件
def write_extract_yaml(self,data):
with open(config.BASE_PATH+'/extract.yml',mode='w',encoding='utf-8') as f:
yaml.dump(data,stream=f,allow_unicode=True)
图17yml文件持久化存储token
图16用户端接口测试点
三. 编写用例(部分接口)
3.1登录接口测试
# 登录:
import requests
import config
# 创建接口类
class LoginAPI:
# 初始化
def __init__(self):
# 指定url基本信息
self.url_login = config.BASE_URL + "/admin/employee/login"
# 登录
def login(self, test_data):
return requests.post(url=self.url_login, json=test_data)
3.2统计接口测试
# 测试统计接口
# 这里只测试用户和营业额
import json
import pytest
import config
from api.statistic import StatisticAPI
from common.yaml_util import YamlUtil
def build_data(json_file):
# 定义空列表
test_data = []
# 打开json文件
with open(json_file, "r") as f:
# 加载json文件数据
json_data = json.load(f)
# 循环遍历测试数据
for case_data in json_data:
# 转换数据格式[{},{}] ==> [(),()]
begin = case_data.get("begin")
end = case_data.get("end")
code = case_data.get("code")
test_data.append((begin,end,code))
# 返回处理之后测试数据
return test_data
class TestStatistic:
def setup_method(self):
self.statistic_api = StatisticAPI()
#测试获取营业额
@pytest.mark.parametrize("begin, end, code", build_data(json_file=config.BASE_PATH + "\\data\\statistic.json"))
def test01_get_turnover(self,begin,end,code):
token = YamlUtil().read_extract_yaml('token')
data = {
"begin": begin,
"end": end,
"code": code
}
headers = {
'token': f'{token}'
}
res = self.statistic_api.turnoverStatistic(test_data=data,headers=headers)
assert code == res.json()[code]
#测试导出文件
def test02_export_excel(self):
token = YamlUtil().read_extract_yaml('token')
headers = {
'token': f'{token}'
}
response = self.statistic_api.exportExcel(headers=headers)
# 检查响应的状态码是否为200
assert response.status_code == 200, "导出文件接口请求失败"
3.3图片上传接口测试
import pytest
import requests
import config
from common.yaml_util import YamlUtil
# 上传成功
def test01_upload_success():
token = YamlUtil().read_extract_yaml('token')
headers = {
'token': f'{token}'
}
f = open(config.BASE_PATH + "/data/test.jpg", "rb")
response = requests.post(url=config.BASE_URL+'/admin/common/upload',files={"file": f},headers=headers)
assert response.status_code == 200
# 文件类型不对
def test02_upload_failure():
token = YamlUtil().read_extract_yaml('token')
headers = {
'token': f'{token}'
}
f = open(config.BASE_PATH + "/data/git.doc", "rb")
response = requests.post(url=config.BASE_URL+'/admin/common/upload',files={"file": f},headers=headers)
assert response.status_code == 200
# 图片大小过大
def test03_upload_failure():
token = YamlUtil().read_extract_yaml('token')
headers = {
'token': f'{token}'
}
f = open(config.BASE_PATH + "/data/big.jpg", "rb")
response = requests.post(url=config.BASE_URL+'/admin/common/upload',files={"file": f},headers=headers)
assert response.status_code == 200
# 图片数据为空
def test03_upload_failure():
token = YamlUtil().read_extract_yaml('token')
headers = {
'token': f'{token}'
}
response = requests.post(url=config.BASE_URL+'/admin/common/upload',files={"file": None},headers=headers)
assert response.status_code == 200
3.4菜品分页查询接口测试
#测试菜品分页查询接口
import json
import pytest
import config
from api.dish import DishAPI
from common.yaml_util import YamlUtil
def build_data(json_file):
# 定义空列表
test_data = []
# 打开json文件
with open(json_file, "r") as f:
# 加载json文件数据
json_data = json.load(f)
# 循环遍历测试数据
for case_data in json_data:
# 转换数据格式[{},{}] ==> [(),()]
begin = case_data.get("page")
end = case_data.get("pageSize")
code = case_data.get("name")
category = case_data.get("categoryId")
status = case_data.get("status")
total = case_data.get("total")
test_data.append((begin,end,code,category,status,total))
# 返回处理之后测试数据
return test_data
class TestDish:
def setup_method(self):
self.dish_api = DishAPI()
@pytest.mark.parametrize("page,pageSize,name,categoryId,status,total", build_data(json_file=config.BASE_PATH + "\\data\\dishPage.json"))
def test_dish_page(self,page,pageSize,name,categoryId,status,total):
token = YamlUtil().read_extract_yaml('token')
headers = {
'token': f'{token}'
}
testData = {
"page": page,
"pageSize": pageSize,
"name": name,
"categoryId": categoryId,
"status": status
}
response = self.dish_api.page_search(headers=headers,test_data=testData)
assert response.json()['data']['total'] == total
四. 批量执行用例并使用allure生成测试报告
图18测试报告