Roller: 抽奖系统测试的幕后剧本-测试报告

article/2025/7/28 22:54:54

抽奖系统 - 测试报告

项目名称:抽奖系统
测试人员:LlvZi
测试时间:2025年5月25 - 2025年6月1


一、项目概述

该项目是一个操作简便、安全可靠的抽奖系统 。主要业务是抽奖,并支持管理员管理用户、奖品和抽奖活动,以配置抽奖内容。抽奖操作由管理员进行,支持依次抽取配置好的奖品和人数,并保证每人最多中一次奖 。系统对异常情况进行了处理,并对中奖人发送短信和邮件通知。项目采用了分层分模块设计,技术栈包括 Spring Boot3、JDK 17、MySQL、MyBatis、Redis、RabbitMQ、SLF4J + logback 等。


二、测试目标

  1. 验证抽奖系统各项核心功能(用户管理、奖品管理、活动管理、抽奖流程)是否符合需求。
  2. 确保系统在正常、异常及边界条件下均能稳定运行,特别是抽奖过程中的唯一性保证。
  3. 验证抽奖接口的异步处理及事务一致性。
  4. 验证系统安全性场景(如:身份验证、隐私数据加密)。
  5. 检查中奖通知(短信、邮件)的及时性和准确性。

三、测试范围

模块名称涵盖功能
用户模块注册、登录、信息管理、身份验证 (JWT)
奖品模块奖品配置、状态管理
活动模块活动创建、配置 (奖品、人员)、状态维护
抽奖模块抽奖操作、异步处理、异常处理、唯一性保证
通知模块短信通知、邮件通知
接口测试所有REST接口状态码与返回结构校验
数据安全与隐私保护密码加密 (加盐哈希)、手机号加密

四、测试方法与工具

类型工具或技术栈
功能测试Postman + 手动测试
接口测试Postman
单元测试编写测试代码验证模块正确性
安全性测试页面强制登录、抽奖异常后的奖品唯一性校验
日志分析SLF4J + logback 记录和修复问题
用例管理Excel、XMind

五、测试环境

环境项配置
操作系统Windows / Linux
数据库MySQL
Java版本JDK 17
后端框架Spring Boot3
缓存Redis
消息队列RabbitMQ
日志框架SLF4J + Logback
应用部署阿里云服务器部署
测试工具版本Postman v10、Selenium 4.0

六、测试用例统计

| 测试类型   | 用例数    | 通过数    | 失败数    | 覆盖率(估算) |
| ------ | ------ | ------ | ------ | ------- |
| 功能测试   | XX     | XX     | XX     | XX%     |
| 接口测试   | XX     | XX     | XX     | XX%     |
| 单元测试   | XX     | XX     | XX     | XX%     |
| 安全性测试  | XX     | XX     | XX     | XX%     |
| **总计** | **XX** | **XX** | **XX** | **XX%** |


七、缺陷分析(Bug记录)

Bug编号模块严重程度问题描述状态
BUG-001抽奖模块(示例) 极端并发情况下,可能出现一人中多次奖的情况待复测
BUG-002通知模块(示例) 邮件通知发送失败时,未提供重试机制待修复
BUG-003登录模块(示例) JWT token 过期后,前端未及时引导用户重新登录待修复
BUG-004异步处理(示例) 死信队列消息处理后,日志记录不够详细已修复

八、结论与建议

✅ 测试结论:

抽奖系统核心功能基本稳定,能够支持基本的抽奖活动需求。异步抽奖设计有效提升了用户体验,事务一致性和消息可靠性通过回滚和死信队列得到保障。身份验证和数据加密措施在一定程度上保障了系统安全。

🔧 建议:

  1. 加强并发测试: 针对抽奖场景进行更严格的并发测试,确保在高并发下抽奖公平性和唯一性的持续有效。
  2. 优化消息通知的重试机制: 进一步完善短信和邮件通知的重试策略和失败告警机制,确保通知的送达率。
  3. 提升前端错误处理和用户体验: 针对异步抽奖接口返回成功后前端的展示,可以增加更丰富的兜底方案,例如在数据未完全落库前提供加载状态或更友好的提示。
  4. 探索更全面的安全测试: 考虑引入自动化安全扫描工具,进一步发现潜在的安全漏洞,如XSS、CSRF等。
  5. 完善日志监控和告警: 针对异步处理、死信队列等关键流程,设置更细致的日志级别和告警,便于及时发现和解决问题。

九、附录

  • 测试用例Excel文档 (部分)

  • 在这里插入图片描述

  • Postman 接口测试集合
    在这里插入图片描述

  • 项目部署文档



*部分代码展示:

package tests;import common.Utils;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;import java.time.Duration;public class BloginTest extends Utils {public static String url = "http://60.205.7.136:8082/blogin.html";public BloginTest() {};public void LoginTest() throws InterruptedException {driver.get(url);// 首先验证标题String expectedTitle = driver.getTitle();assert expectedTitle.equals("管理员登录界面");// 模拟登陆测试driver.findElement(By.cssSelector("#phoneNumber")).sendKeys("18039295275");driver.findElement(By.cssSelector("#password")).sendKeys("123456");driver.findElement(By.cssSelector("#loginForm > button")).click();Thread.sleep(1000);String expectedTitle1 = driver.getTitle();System.out.println(expectedTitle1);assert expectedTitle1.equals("后台官迷");System.out.println("模拟登陆成功!");}// 检查是否加载成功public void LoginRight() throws InterruptedException {driver.get(url);// 手机号 + 密码登录// 检查是否有 user和 passworddriver.findElement(By.cssSelector("#phoneNumber")).sendKeys("18039295275");driver.findElement(By.cssSelector("#password")).sendKeys("123456");System.out.println("手机号+密码登录界面测试成功!");// Thread.sleep(2000);// 验证码登录driver.findElement(By.cssSelector("body > div > div.login-container.col-sm-6.col-md-6.col-lg-5.col-xl-5 > div.tab-box > span:nth-child(2)")).click();//Thread.sleep(1000);driver.findElement(By.cssSelector("#loginMobile")).sendKeys("18039295275");driver.findElement(By.cssSelector("#getVerificationCode"));driver.findElement(By.cssSelector("#verificationCode")).sendKeys("123456");System.out.println("手机号+验证码登录界面测试成功!");}// 正常登录  验证码登录由于无法使用阿里云短信服务故无法验证  --》直接看手机是否收到手机号public void LoginSubmitRight() {driver.findElement(By.cssSelector("body > div > div.login-container.col-sm-6.col-md-6.col-lg-5.col-xl-5 > div.tab-box > span.tab-span.active")).click();driver.navigate().refresh();// 手机号 + 密码登录driver.findElement(By.cssSelector("#phoneNumber")).sendKeys("18039295275");driver.findElement(By.cssSelector("#password")).sendKeys("123456");driver.findElement(By.cssSelector("#loginForm > button")).click();String expectedTitle1 = driver.getTitle();assert expectedTitle1.equals("后台管理");System.out.println("手机号+密码正常登录成功");}/*** 登录失败测试--手机+密码登录*/public void LoginSubmitError1() throws InterruptedException {driver.findElement(By.cssSelector("body > div.header-box > div.user-box > div > span")).click();// 返回上一界面  因为上一个测试是“登录成功”,成功之后跳转到list界面了
//        driver.navigate().back();
//        driver.navigate().refresh();Thread.sleep(2000);// 用户名正确 + 密码错误driver.findElement(By.cssSelector("#phoneNumber")).sendKeys("18039295275");driver.findElement(By.cssSelector("#password")).sendKeys("123451");driver.findElement(By.cssSelector("#loginForm > button")).click();// 由于设置的有弹窗需要解决一下  alert只能通过显示等待获取WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));Alert alert = wait.until(ExpectedConditions.alertIsPresent());String text = alert.getText();assert text.equals("登录失败!密码错误");alert.accept();System.out.println("登录失败--用户名正确--密码错误--验证成功");// driver.quit();}/*** 登录失败测试--用户名 || 密码为空*/public void LoginSubmitError2() throws InterruptedException {// 刷新  重新输入driver.navigate().refresh();// Thread.sleep(3000);driver.findElement(By.cssSelector("#phoneNumber")).sendKeys("");driver.findElement(By.cssSelector("#password")).sendKeys("123451");driver.findElement(By.cssSelector("#loginForm > button")).click();String phoneNumberIsNULLText = driver.findElement(By.cssSelector("#phoneNumber-error")).getText();phoneNumberIsNULLText.equals("请输入您的手机号");System.out.println("登录失败测试--用户名 || 密码为空 验证成功");}/*** 登录失败测试--检查是否存在sql注入问题  弹出"登录失败,密码或者用户名错误!"*/public void LoginSubmitError3() throws InterruptedException {// 刷新  重新输入driver.navigate().refresh();// Thread.sleep(3000);driver.findElement(By.cssSelector("#phoneNumber")).sendKeys("admin' -- ");driver.findElement(By.cssSelector("#password")).sendKeys("123456");driver.findElement(By.cssSelector("#loginForm > button")).click();// 由于设置的有弹窗需要解决一下  alert只能通过显示等待获取WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(20));Alert alert = wait.until(ExpectedConditions.alertIsPresent());String text = alert.getText();assert text.equals("登录失败!登录方式不存在");alert.accept();System.out.println("登录失败测试--检查是否存在sql注入问题--sql注入验证成功");// driver.quit();}public void registerTest() {driver.navigate().refresh();driver.findElement(By.cssSelector("body > div > div.login-container.col-sm-6.col-md-6.col-lg-5.col-xl-5 > div.register-link > a")).click();String expectedTitle = driver.getTitle();assert expectedTitle.equals("注册页面");System.out.println("成功进入注册页面");driver.findElement(By.cssSelector("#name")).sendKeys("yj");driver.findElement(By.cssSelector("#mail")).sendKeys("2314394022@qq.com");driver.findElement(By.cssSelector("#phoneNumber")).sendKeys("18039295222");driver.findElement(By.cssSelector("#password")).sendKeys("123456");driver.findElement(By.cssSelector("#registerForm > button")).click();System.out.println("注册成功!");WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));Alert alert = wait.until(ExpectedConditions.alertIsPresent());alert.accept();}
}
package tests;import common.Utils;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;import java.time.Duration;/*** 创建活动接口测试*/
public class CreateActivityTest extends Utils {public static String url =  "http://60.205.7.136:8082/admin.html";public CreateActivityTest() {}public void createActivityRight() throws InterruptedException {// 假设已经登录driver.findElement(By.cssSelector("#createActivity")).click();driver.switchTo().frame("contentFrame");driver.findElement(By.cssSelector("#activityName")).sendKeys("test2");driver.findElement(By.cssSelector("#description")).sendKeys("test2");Thread.sleep(2000);// 点击圈选奖品--跳出奖品选择模态框(重点是如何对模态框进行补货)driver.findElement(By.cssSelector("#buttonPrizes")).click();WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(20));WebElement prizeModal = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("prizesModal")));prizeModal.findElement(By.cssSelector("#prize-20")).click();// 模拟圈选一个奖品prizeModal.findElement(By.cssSelector("#prizesModal > div > div.form-btn-box > button.btn.btn-primary")).click();Thread.sleep(2000);// 点击全选人员driver.findElement(By.cssSelector("#buttonUsers")).click();WebDriverWait wait1 = new WebDriverWait(driver, Duration.ofSeconds(20));WebElement userModal = wait1.until(ExpectedConditions.visibilityOfElementLocated(By.id("usersModal")));userModal.findElement(By.cssSelector("#user-41")).click();userModal.findElement(By.cssSelector("#usersModal > div > div.form-btn-box > button.btn.btn-primary")).click();Thread.sleep(2000);driver.findElement(By.cssSelector("#createActivity")).click();Alert alert = wait1.until(ExpectedConditions.alertIsPresent());alert.accept();System.out.println("活动创建成功!");}
}package tests;import common.Utils;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;import java.time.Duration;public class CreatePrizeTest extends Utils {public static String url =  "http://60.205.7.136:8082/admin.html";public CreatePrizeTest() {}public void createPrizeRight() {// 假设已经登录driver.findElement(By.cssSelector("body > div.cont-box > div.sidebar > ul > li:nth-child(2) > ul > li:nth-child(2) > a")).click();driver.switchTo().frame("contentFrame");driver.findElement(By.cssSelector("#prizeName")).sendKeys("华为手机");driver.findElement(By.cssSelector("#price")).sendKeys("5000");driver.findElement(By.cssSelector("#description")).sendKeys("遥遥领先");WebElement element = driver.findElement(By.xpath("/html/body/div/div/div/div[2]/div/div/input"));element.sendKeys("C:\\Users\\绿字\\Desktop\\抽奖系统\\OIP-C (1).jpg");driver.findElement(By.cssSelector("body > div > button")).click();WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(20));Alert alert = wait.until(ExpectedConditions.alertIsPresent());alert.accept();System.out.println("奖品上传成功");}}

http://www.hkcw.cn/article/YxHppPoVGP.shtml

相关文章

智语心桥:当AI遇上“星星的孩子”,科技如何点亮沟通之路?

目录: 引言:当科技的温度,遇见“星星的孩子”“智语心桥”:一座为孤独症儿童搭建的AI沟通之桥核心技术探秘:AI如何赋能“读心”与“对话”?个性化魔法:AI如何实现“千人千面”的精准干预?应用场景畅想:从家庭到机构,AI的全方位支持为什么是“智语心桥”?——价值、可…

c++学习之---模版

目录 一、函数模板: 1、基本定义格式: 2、模版函数的优先匹配原则: 二、类模板: 1、基本定义格式: 2、类模版的优先匹配原则(有坑哦): 3、缺省值的设置: 4、ty…

GESP2024年3月认证C++二级( 第三部分编程题(1)乘法问题)

参考程序&#xff1a; #include <iostream> // 引入输入输出库 using namespace std; // 使用标准命名空间&#xff0c;简化代码int main() {int n; // 存储输入的数字个数cin >> n; // 读入 nlong long product 1; // 用 long long 存…

NX811NX816美光颗粒固态NX840NX845

NX811NX816美光颗粒固态NX840NX845 美光NX系列固态硬盘颗粒深度解析&#xff1a;技术、性能与市场全景透视 一、技术架构与核心特性解析 1. NX811/NX816&#xff1a;入门级市场的平衡之选 技术定位&#xff1a;基于176层TLC&#xff08;Triple-Level Cell&#xff09;3D NAN…

6、运算放大器—共模抑制比(七)

目录 1、共模抑制比&#xff08;CMRR&#xff09;的定义 2、共模误差推导 3、电阻对共模误差的影响 4、参数特性 运算放大器&#xff08;运放&#xff09;的共模抑制比&#xff08;Common-Mode Rejection Ratio, CMRR&#xff09;是衡量其抑制共模信号能力的关键参数&…

“日本7月5日末日论”疯传 漫画预言引发社会焦虑

最近,网上关于日本“末日论”的讨论引起了广泛关注。据说2025年7月5日日本将遭遇毁灭性灾难,三分之一的国土会被海水吞没,连中国游客都忙着退酒店改行程。这一说法源自30年前的一部漫画——《我所看见的未来》,作者自称梦见了未来。漫画家龙树谅曾“预言”过2011年的东日本…

卢伟冰:竞争从来不是小米面临的挑战 更重视内部优化与用户距离

小米集团发布第一季度财报后,总裁卢伟冰与投资人进行了深入交流。面对投资人关于小米未来挑战的问题,卢伟冰提出了两点看法。他指出,随着小米业务规模和组织规模的扩大,公司需要确保不偏离其价值观,并保持与用户的紧密联系。同时,小米的管理体系也需要不断升级,以匹配业…

郑钦文将第8次对阵萨巴伦卡 再战老对手

在2025年法网女单1/8决赛中,头号种子萨巴伦卡以7-5和6-3的比分击败阿尼西莫娃,顺利晋级八强。这已经是萨巴伦卡连续第三年进入法网八强,并且她在最近参加的十个大满贯赛事中都至少闯入了八强。接下来,萨巴伦卡将与中国选手郑钦文交手。两人此前已经有过七次对决,郑钦文仅在…

DeepSeek R1 重磅升级,天工超级智能体 App 上线,Claude 解锁语音新体验!| AI Weekly 5.26-6.1

&#x1f4e2;本周AI快讯 | 1分钟速览&#x1f680; 1️⃣ &#x1f9e0; DeepSeek R1-0528 重磅升级 &#xff1a;推理能力接近 o3 和 Gemini 2.5 Pro&#xff0c;AIME 2025 数学测试准确率从 70% 飙升至 87.5%&#xff0c;幻觉率降低 45-50%。 2️⃣ &#x1f50d; 阿里通义…

亚马逊FBA新规下:1个模型算准补货量,自动预警断货危机

随着亚马逊对库存管理日趋严格&#xff0c;尤其是近期FBA库存限制政策的频频调整&#xff0c;越来越多卖家开始重视智能补货的重要性。断货不仅会影响销量&#xff0c;还可能导致排名下降甚至失去黄金购物车。如何在FBA新规下精准补货、避免资金积压或断货风险&#xff1f;答案…

电工基础【3】星形(Y) 和 三角形(△) 电路切换

05 星三角形启动 (星三角启动) 1、电机星形(Y)的工作原理 2、电机三角形(△)的工作原理 3、电机星三角形启动电气原理图的讲解 4、时间继电器的讲解 -----小记----- 星三角也是很经常用&#xff0c;是很经典电路。 好&#xff0c;我们讲这个课之前的话&#xff0c;我们先了…

JS基础3—定时器

定时器目录 定时器周期定时器延迟定时器 定时器实践转盘旋转动画轮播图实现 定时器 周期定时器 setInterval() 每隔指定时间重复执行回调函数 const intervalId setInterval(callback, interval, [arg1], [arg2], ...);参数&#xff1a; callback&#xff1a;要执行的函数…

使用通义万相Wan2.1进行视频生成

使用通义万相Wan2.1进行视频生成 源代码准备运行环境准备创建Python虚拟环境并激活安装依赖包 模型下载生成视频官网的视频生成例子简单描述场景视频生成示例详细描述场景视频生成示例 最近通义万相开源了其视频生成模型。模型有两个版本&#xff0c;一个是1.3B的&#xff0c;一…

最新扣子(Coze)案例教程:小红书爆款书单推荐视频工作流!3分钟10个爆款视频,文学赛道书籍推荐视频日更必备工具,完全免费教程

大家好&#xff0c;我是斜杠君。 最近&#xff0c;星球群里有做小红书文学赛道的博主咨询&#xff0c;每天都在为制作书单的视频找素材、配背景、配音效等&#xff0c;产出量很低。想看看是否可以通过扣子工作流的方式&#xff0c;只要定制好一个工作流的流程&#xff0c;就可…

uniapp [安卓苹果App端] - 实现获取手机摄像头权限+调用相机拍照或拍视频+保存图片视频到相册,检测权限手机摄像头功能是否开启并引导用户同意授权,uniApp app端调用本机开启摄像头授权

前言 网上的教程乱七八糟且兼容性太差,本文提供优质示例。 在 uni-app App端(安卓APP | 苹果APP)开发中,详解在app平台端实现获取手机摄像头权限查询,有权限则开启本机摄像头完成拍摄或录制视频+保存媒体文件到相册等操作,反之无权限则提示开启摄像头与引导用户授权操作,…

【人工智能】深度学习利用人工智能进行VRT视频修复

目录 一、前提二、VRT的重要性和研究背景2. 1 VRT的背景&#xff1a;2.2 VRT的重要性&#xff1a; 三、视频修复概述3.1 定义与目标3.2 与单图像修复的区别3.3 对时间信息利用的需求 四、VRT模型详解4.1 整体框架4.2 多尺度设计和模块功能4.3 关键创新点 五、实验结果5.1 VRT在…

2024年视频号生态洞察报告 | 友望数据发布

2024年视频号直播带货达人和直播销售数据同步增长&#xff0c;直播电商规模不断扩张。从友望数据品类大盘看&#xff0c;服饰内衣、美妆护肤品类高速增长&#xff0c;电商生态持续繁荣。 微信小店的升级&#xff0c;特别是【送礼物】功能的上线&#xff0c;进一步打通社交与电商…

OpenCV从入门到精通:OpenCV安装、配置、依赖安装、基本语法、常用方法详解

OpenCV从入门到精通&#xff1a;OpenCV安装、配置、依赖安装、基本语法、常用方法详解 引言 OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源的跨平台计算机视觉库&#xff0c;提供了丰富的图像和视频处理算法接口&#xff0c;支持 Python、C、…

瑞芯微 RK 系列 RK3588 使用 ffmpeg-rockchip 实现 MPP 视频硬件编解码-代码版

前言 在上一篇文章中&#xff0c;我们讲解了如何使用 ffmpeg-rockchip 通过命令来实现 MPP 视频硬件编解码和 RGA 硬件图形加速&#xff0c;在这篇文章&#xff0c;我将讲解如何使用 ffmpeg-rockchip 用户空间库&#xff08;代码&#xff09;实现 MPP 硬件编解码。 本文不仅适…

【计算机视觉】OpenCV实战项目:基于OpenCV的车牌识别系统深度解析

基于OpenCV的车牌识别系统深度解析 1. 项目概述2. 技术原理与算法设计2.1 图像预处理1) 自适应光照补偿2) 边缘增强 2.2 车牌定位1) 颜色空间筛选2) 形态学操作3) 轮廓分析 2.3 字符分割1) 投影分析2) 连通域筛选 2.4 字符识别 3. 实战部署指南3.1 环境配置3.2 项目代码解析 4.…