抽奖系统测试报告

抽奖系统测试报告

1.项目概述

1.1项目背景

lottery-system(抽奖系统)是一个基于 Spring Boot 3 架构的在线抽奖管理系统,旨在为企业和组织提供活动管理、奖品管理、用户管理及抽奖流程等核心功能。系统采用前后端分离架构,支持多用户并发访问,提供友好的用户交互界面和高效的异步抽奖服务。

1.2 项目目标

功能目标:提供完整的抽奖管理功能,包括活动创建与管理、奖品配置、用户管理、抽奖执行、中奖记录查询与分享等

性能目标:支持高并发抽奖请求,确保系统在高负载下的稳定性和响应速度,通过异步处理和缓存优化提升系统吞吐量

用户体验目标:提供流畅的用户交互体验,快速响应用户操作,支持多种登录方式,提供清晰的中奖结果展示

1.3 业务场景

系统主要服务于以下业务场景:

用户登录认证:支持密码登录和邮箱验证码登录,确保用户身份安全

活动管理:管理员可创建抽奖活动,配置活动名称、参与人员、奖品数量等参数,支持活动列表查询和分页展示

奖品管理:管理员可创建和管理奖品信息,包括奖品名称、图片、数量等,支持奖品列表查询和分页展示

用户管理:管理员可创建用户、查看用户列表,支持按用户ID搜索等操作

抽奖流程:用户或管理员发起抽奖后,系统异步执行抽奖逻辑,确保公平性和系统性能

中奖记录查询:支持查看中奖名单,可按活动维度或奖品维度查询,支持中奖结果分享功能

1.4 技术特点

Spring Boot 3 架构:采用 Spring Boot 3.5.4 框架,基于 Java 17,提供现代化的开发体验和性能优化

前后端分离:前端使用静态 HTML 页面,后端使用 Spring Boot 提供 RESTful API 服务

异步处理:抽奖流程采用 RabbitMQ 消息队列实现异步处理,提升系统吞吐量和响应速度

缓存优化:使用 Redis 缓存热点数据(如验证码、活动信息 中奖记录等),提升查询性能,降低数据库压力

数据持久化:使用 MyBatis 作为 ORM 框架,MySQL 作为关系型数据库,支持数据加密存储

邮件服务:集成 Spring Mail 实现邮箱验证码发送功能,支持 SMTP 协议

安全认证:使用 JWT(JSON Web Token)实现用户身份认证,支持 Token 过期管理

高并发支持:通过线程池配置、消息队列异步处理、Redis 缓存等技术保障高并发场景下的系统稳定性

图片服务:支持奖品图片上传和管理,提供本地文件存储方案

2.项目结构

  • 后端代码:src/main/java/com/fgs/demo
    • controller:登录、活动、奖品、用户、抽奖等接口。
    • service:业务实现与状态管理、MQ 接收、验证码/图片等服务。
    • dao:MyBatis DO/Mapper,含加密类型处理器。
    • common:统一返回体、异常、拦截器、配置、工具类(JWT、Redis、Mail、Captcha 等)。
  • 前端静态页:src/main/resources/static(login/admin/create-activity/prizes-list/draw 等页面及样式资源)。
  • 配置:src/main/resources/application.yml(MySQL、Redis、RabbitMQ、SMTP 等),logback-spring.xml
  • 自动化测试:src/test/java/com/fgs/demo 下若干单元/集成测试类(启动、自定义工具、DAO、服务等)。

3.测试环境

  • 硬件/操作系统:Windows 11。
  • 软件版本:JDK 17;Maven 3.9+;MySQL 8.0.39;Redis7.4 ;RabbitMQ3.8.30 ;SMTP(QQ 邮箱,SSL 465)。
  • 运行配置:spring.profiles.active=dev;数据源账户默认 root/1302743585,图片根路径 D:/PIC
  • 启动步骤:mvn clean packagejava -jar target/lottery-system-0.0.1-SNAPSHOT.jar 或 IDE 直接运行 LotterySystemApplication

4.功能测试

4.1手动测试(按照页面)

测试用例





4.1.1登录页测试
密码登录
正确登录
  1. 输入正确的手机号+密码,点击登录
    预期结果 :登录成功,页面跳转至管理员页面。
    实际结果

    状态:通过

错误登录
  1. 手机号正确,不输入密码直接点击登录
    预期结果 :密码输入框下红色字体提示"请输入密码",页面未变动。
    实际结果

    状态:通过

  2. 手机号和密码均未输入,直接点击登录
    预期结果 :账号输入框和密码输入框下红色字体提示"请输入手机号&密码",页面未变动。
    实际结果

    状态:通过

  3. 不输入手机号,仅输入密码后点击登录
    预期结果 :账号输入框下红色字体提示"请输入账号",页面未变动。
    实际结果

    状态:通过

验证码登录
正确登录
  1. 输入正确的 QQ 邮箱,点击获取验证码,随后输入正确验证码并登录
    预期结果 :登录成功,页面跳转至管理员页面;Redis 中先存储验证码,登录成功后删除该缓存。
    实际结果

    登录成功后:

    状态:通过

错误登录
  1. 输入不符合格式的 QQ 邮箱,点击获取验证码
    预期结果 :弹窗提示"邮箱格式有误 请重新输入",验证码按钮倒计时不开始,页面无跳转。
    实际结果

    状态:通过

  2. 输入符合格式的 QQ 邮箱,点击获取验证码后输入错误验证码登录
    预期结果 :页面提示验证码发送成功;点击登录按钮后弹窗"登录失败/登录信息有误",页面不跳转。
    实际结果


    状态:通过

管理员注册
  1. 点击注册按钮 → 进入管理员注册页
    预期结果 :正确填写所有必填信息后点击注册 弹窗提示注册成功 数据库信息正确写入
    实际结果

    状态:通过

4.1.2 活动页测试
列表与翻页
  1. 获取活动列表-展示 → 进入活动列表页
    预期结果 :显示全部活动,未结束活动排在已结束前,数据正常。
    实际结果

    状态:不通过

  2. 翻页正确 → 点击下一页/上一页
    预期结果 :数据正常展示,每页个数符合预期。
    实际结果

    第一页:

    下一页:

    状态:通过

  3. 翻页错误(首页点上一页) → 位于第一页点击上一页
    预期结果 :弹窗"已经是第一页"。
    实际结果

    状态:通过

  4. 翻页错误(尾页点下一页) → 位于最后一页点击下一页
    预期结果 :弹窗"已经是最后一页"
    实际结果

    状态:通过

新建活动
  1. 正确:填昵称/描述,选人员+奖品 → 点击创建
    预期结果 :弹窗"创建成功!",跳转列表,列表含新活动,DB 与 Redis 写入正常。
    实际结果

    缓存正确写入:

    数据库正确写入:

    状态:通过

  2. 重复昵称其余正确 → 点击创建
    预期结果 :弹窗提示"创建失败!活动昵称已存在 请使用其他名称",无跳转,DB/缓存不写入。
    实际结果



    状态:通过

  3. 不填任何信息创建 → 点击创建
    预期结果 :昵称、描述下红字"请输入对应信息",无弹窗,DB/缓存不写入。
    实际结果


    状态:通过

  4. 填昵称/描述,不选人员和奖品 → 点击创建
    预期结果 :弹窗"请至少选择一个奖品!",DB/缓存不写入。
    实际结果



    状态:通过

  5. 填昵称/描述,选奖品未选人员 → 点击创建
    预期结果 :弹窗"请至少选择一个人员, 人员数量应大于等于奖品总量!",DB/缓存不写入。
    实际结果



    状态:通过

4.1.3 奖品页测试
列表与翻页
  1. 获取奖品列表-展示 → 进入奖品列表页
    预期结果 :显示全部奖品,数据正常。
    实际结果

    状态:通过

  2. 翻页正确(下一页) → 点击上一页
    预期结果 :数据正常展示,每页数量符合预期。
    实际结果

    状态:通过

  3. 翻页正确(上一页) → 点击上一页
    预期结果 :数据正常展示,每页数量符合预期。
    实际结果


    状态:通过

  4. 翻页错误(首页点上一页) → 位于第一页点击上一页
    预期结果 :弹窗"已经是第一页"。
    实际结果
    状态:未执行

  5. 翻页错误(尾页点下一页) → 位于最后一页点击下一页
    预期结果 :弹窗"当前已经是最后一页了哦"。
    实际结果

    状态:通过

新建奖品
  1. 正确:合法昵称/描述及必填信息 → 点击创建
    预期结果 :弹窗提示"创建成功!",跳转列表,含新奖品,DB 正确写入。
    实际结果


    状态:通过

  2. 重复昵称创建奖品 → 点击创建
    预期结果 :弹窗"奖品昵称已存在 请使用其他昵称",无跳转,DB/缓存不写入。
    实际结果

    未写入新的奖品
    状态:通过

  3. 不填信息创建 → 点击创建
    预期结果 :昵称、描述下红字"请输入对应信息",无弹窗
    实际结果

    状态:通过

4.1.4 用户页测试
用户管理
  1. 获取用户列表 → 进入用户列表页
    预期结果 :展示全部用户信息,数据正常。
    实际结果

    状态:通过

  2. 新增用户-正确:合法昵称/描述及必填信息 → 点击创建
    预期结果 :弹窗"创建成功!",跳转用户列表,含新用户,DB 写入正常。
    实际结果



    状态:通过

  3. 新增用户-重复姓名其余信息正确 → 点击创建
    预期结果 :弹窗提示"该姓名已存在,请重新输入",无跳转
    实际结果

    状态:通过

  4. 新增用户-不填信息新增 → 点击创建
    预期结果 :姓名、邮箱、手机号下红字"请输入对应信息",无弹窗。
    实际结果

    状态:通过

  5. 新增用户-邮箱格式错误注册 → 点击创建
    预期结果 :邮箱下红字提示"请输入有效的邮箱地址",无跳转,DB不写入
    实际结果

    状态:通过

4.1.5 抽奖页测试
抽奖与结果
  1. 开始抽奖 → 点击开始
    预期结果 :姓名轮流闪动,抽奖记录数据写入 DB 和缓存正确。
    实际结果

    数据库正确写入

    缓存正确写入:

    状态:通过

  2. 查看中奖名单 → 进入中奖名单页
    预期结果 :新页面显示活动昵称,中奖名单展示正常。
    实际结果

    状态:不通过

  3. 分享抽奖结果 → 点击分享结果
    预期结果 :弹窗"链接已复制到粘贴板",新窗口访问数据正常。
    实际结果

    新建页面访问正常:

状态:通过

4.2自动化测试

4.2.1基础测试类

提供WebDriver的初始化和清理功能。

代码如下:

java 复制代码
package com.fgs.demo.selenium;

import io.github.bonigarcia.wdm.WebDriverManager;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.time.Duration;

/**
 * Selenium测试基类
 * 提供WebDriver的初始化和清理
 */
public class BaseSeleniumTest {
    
    protected WebDriver driver;
    protected WebDriverWait wait;
    protected String baseUrl = "http://localhost:8080";
    
    @BeforeEach
    public void setUp() {
        // 使用WebDriverManager自动管理ChromeDriver
        WebDriverManager.chromedriver().setup();
        
        // 配置Chrome选项
        ChromeOptions options = new ChromeOptions();
        options.addArguments("--start-maximized");
        options.addArguments("--disable-blink-features=AutomationControlled");
        options.addArguments("--disable-infobars");
        
        driver = new ChromeDriver(options);
        // 设置隐式等待
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
        // 设置显式等待
        wait = new WebDriverWait(driver, Duration.ofSeconds(15));
    }
    
    @AfterEach
    public void tearDown() {
        if (driver != null) {
            driver.quit();
        }
    }
    
    /**
     * 等待指定时间(毫秒)
     */
    protected void sleep(long milliseconds) {
        try {
            Thread.sleep(milliseconds);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}
4.2.2登录页测试

包含以下测试用例:

  • testPasswordLogin_Success: 测试正确密码登录
  • testPasswordLogin_EmptyPassword: 测试密码为空的情况
  • testPasswordLogin_EmptyPhone: 测试手机号为空的情况
  • testPasswordLogin_EmptyBoth: 测试手机号和密码都为空的情况
  • testVerificationCodeLogin_InvalidEmail: 测试验证码登录-邮箱格式错误
  • testVerificationCodeLogin_ValidEmail: 测试验证码登录-正确邮箱格式
    代码如下:
java 复制代码
package com.fgs.demo.selenium;

import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;

import static org.junit.jupiter.api.Assertions.*;

/**
 * 登录页测试类
 * 测试密码登录和验证码登录功能
 */
public class LoginPageTest extends BaseSeleniumTest {
    
    @Test
    public void testPasswordLogin_Success() {
        // 测试正确登录
        driver.get(baseUrl + "/blogin.html");
        
        // 输入手机号
        WebElement phoneInput = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("loginName")));
        phoneInput.clear();
        phoneInput.sendKeys("17527167018"); // 需要替换为实际存在的测试账号
        
        // 输入密码
        WebElement passwordInput = driver.findElement(By.id("password"));
        passwordInput.clear();
        passwordInput.sendKeys("123456"); // 需要替换为实际密码
        
        // 点击登录按钮
        WebElement loginButton = driver.findElement(By.cssSelector("#loginForm button[type='submit']"));
        loginButton.click();
        
        // 等待页面跳转或显示结果
        sleep(2000);
        
        // 验证是否跳转到admin页面或显示成功消息
        String currentUrl = driver.getCurrentUrl();
        assertTrue(currentUrl.contains("admin.html") || currentUrl.contains("blogin.html"), 
            "登录后应该跳转到admin页面");
    }
    
    @Test
    public void testPasswordLogin_EmptyPassword() {
        // 测试密码为空的情况
        driver.get(baseUrl + "/blogin.html");
        
        // 输入手机号
        WebElement phoneInput = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("loginName")));
        phoneInput.clear();
        phoneInput.sendKeys("13800138000");
        
        // 不输入密码,直接点击登录
        WebElement loginButton = driver.findElement(By.cssSelector("#loginForm button[type='submit']"));
        loginButton.click();
        
        // 等待验证消息显示
        sleep(1000);
        
        // 验证是否显示错误提示
        WebElement passwordInput = driver.findElement(By.id("password"));
        String validationMessage = passwordInput.getAttribute("validationMessage");
        assertNotNull(validationMessage, "应该显示密码验证错误");
    }
    
    @Test
    public void testPasswordLogin_EmptyPhone() {
        // 测试手机号为空的情况
        driver.get(baseUrl + "/blogin.html");
        
        // 不输入手机号,直接输入密码
        WebElement passwordInput = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("password")));
        passwordInput.clear();
        passwordInput.sendKeys("123456");
        
        // 点击登录按钮
        WebElement loginButton = driver.findElement(By.cssSelector("#loginForm button[type='submit']"));
        loginButton.click();
        
        // 等待验证消息显示
        sleep(1000);
        
        // 验证是否显示错误提示
        WebElement phoneInput = driver.findElement(By.id("loginName"));
        String validationMessage = phoneInput.getAttribute("validationMessage");
        assertNotNull(validationMessage, "应该显示手机号验证错误");
    }
    
    @Test
    public void testPasswordLogin_EmptyBoth() {
        // 测试手机号和密码都为空的情况
        driver.get(baseUrl + "/blogin.html");
        
        // 直接点击登录按钮
        WebElement loginButton = wait.until(ExpectedConditions.elementToBeClickable(
            By.cssSelector("#loginForm button[type='submit']")));
        loginButton.click();
        
        // 等待验证消息显示
        sleep(1000);
        
        // 验证是否显示错误提示
        WebElement phoneInput = driver.findElement(By.id("loginName"));
        String phoneValidation = phoneInput.getAttribute("validationMessage");
        assertNotNull(phoneValidation, "应该显示手机号验证错误");
    }
    
    @Test
    public void testVerificationCodeLogin_InvalidEmail() {
        // 测试验证码登录 - 邮箱格式错误
        driver.get(baseUrl + "/blogin.html");
        
        // 切换到验证码登录标签
        WebElement codeTab = wait.until(ExpectedConditions.elementToBeClickable(
            By.xpath("//span[contains(text(), '验证码登录')]")));
        codeTab.click();
        
        sleep(500);
        
        // 输入不符合格式的邮箱
        WebElement emailInput = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("loginEmail")));
        emailInput.clear();
        emailInput.sendKeys("invalid-email");
        
        // 点击获取验证码按钮
        WebElement getCodeButton = driver.findElement(By.id("getVerificationCode"));
        getCodeButton.click();
        
        // 等待弹窗显示
        sleep(1000);
        
        // 验证是否显示邮箱格式错误提示(通过alert)
        // 注意:这里需要处理浏览器alert
        try {
            driver.switchTo().alert();
            // 如果alert存在,说明显示了错误提示
            assertTrue(true, "应该显示邮箱格式错误提示");
            driver.switchTo().alert().accept();
        } catch (Exception e) {
            // 如果没有alert,检查页面上的错误提示
            WebElement errorElement = driver.findElement(By.cssSelector(".error"));
            assertNotNull(errorElement, "应该显示错误提示");
        }
    }
    
    @Test
    public void testVerificationCodeLogin_ValidEmail() {
        // 测试验证码登录 - 正确邮箱格式
        driver.get(baseUrl + "/blogin.html");
        
        // 切换到验证码登录标签
        WebElement codeTab = wait.until(ExpectedConditions.elementToBeClickable(
            By.xpath("//span[contains(text(), '验证码登录')]")));
        codeTab.click();
        
        sleep(500);
        
        // 输入正确格式的邮箱
        WebElement emailInput = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("loginEmail")));
        emailInput.clear();
        emailInput.sendKeys("3269804505@qq.com"); // 需要替换为实际测试邮箱
        
        // 点击获取验证码按钮
        WebElement getCodeButton = driver.findElement(By.id("getVerificationCode"));
        getCodeButton.click();
        
        // 等待验证码发送
        sleep(2000);
        
        // 验证按钮文本是否变为倒计时
        String buttonText = getCodeButton.getText();
        assertTrue(buttonText.contains("s") || buttonText.equals("重新获取"), 
            "验证码按钮应该显示倒计时或重新获取");
    }
}
4.2.1活动页测试

包含以下测试用例:

  • testActivityList_Display: 测试活动列表展示
  • testActivityList_Pagination_Next: 测试翻页-下一页
  • testActivityList_Pagination_Previous: 测试翻页-上一页
  • testActivityList_Pagination_FirstPage: 测试第一页点击上一页
  • testCreateActivity_Valid: 测试创建活动-正确信息
  • testCreateActivity_EmptyFields: 测试创建活动-不填信息
  • testCreateActivity_NoPrizes: 测试创建活动-不选择奖品
    代码如下:
java 复制代码
package com.fgs.demo.selenium;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

/**
 * 活动页测试类
 * 测试活动列表、翻页、新建活动等功能
 */
public class ActivityPageTest extends BaseSeleniumTest {
    @BeforeEach
    public void login() {
        // 先登录
        driver.get(baseUrl + "/blogin.html");
        
        // 输入登录信息
        WebElement phoneInput = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("loginName")));
        phoneInput.clear();
        phoneInput.sendKeys("17527167018");
        
        WebElement passwordInput = driver.findElement(By.id("password"));
        passwordInput.clear();
        passwordInput.sendKeys("123456");
        
        WebElement loginButton = driver.findElement(By.cssSelector("#loginForm button[type='submit']"));
        loginButton.click();
        
        // 等待登录完成
        sleep(3000);
    }
    
    @Test
    public void testActivityList_Display() {
        // 测试活动列表展示
        driver.get(baseUrl + "/admin.html");
        sleep(2000);
        
        // 切换到活动列表iframe
        WebElement iframe = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("contentFrame")));
        driver.switchTo().frame(iframe);
        
        // 等待活动列表加载
        sleep(2000);
        
        // 验证活动列表标题
        WebElement title = wait.until(ExpectedConditions.presenceOfElementLocated(By.tagName("h2")));
        assertEquals("活动列表", title.getText(), "应该显示活动列表标题");
        
        // 验证是否有活动项
        List<WebElement> activityItems = driver.findElements(By.cssSelector(".activity-item"));
        assertNotNull(activityItems, "活动列表应该存在");
    }
    
    @Test
    public void testActivityList_Pagination_Next() {
        // 测试翻页 - 下一页
        driver.get(baseUrl + "/admin.html");
        sleep(2000);
        
        driver.switchTo().frame(driver.findElement(By.id("contentFrame")));
        sleep(2000);
        
        // 点击下一页按钮
        WebElement nextButton = wait.until(ExpectedConditions.elementToBeClickable(
            By.xpath("//button[contains(text(), '下一页')]")));
        nextButton.click();
        
        sleep(2000);
        
        // 验证页码是否更新
        WebElement pageInput = driver.findElement(By.id("pageInput"));
        String pageValue = pageInput.getAttribute("value");
        assertTrue(Integer.parseInt(pageValue) > 1, "页码应该增加");
    }
    
    @Test
    public void testActivityList_Pagination_Previous() {
        // 测试翻页 - 上一页
        driver.get(baseUrl + "/admin.html");
        sleep(2000);
        
        driver.switchTo().frame(driver.findElement(By.id("contentFrame")));
        sleep(2000);
        
        // 先跳转到第二页
        WebElement nextButton = wait.until(ExpectedConditions.elementToBeClickable(
            By.xpath("//button[contains(text(), '下一页')]")));
        nextButton.click();
        sleep(2000);
        
        // 点击上一页按钮
        WebElement previousButton = wait.until(ExpectedConditions.elementToBeClickable(
            By.xpath("//button[contains(text(), '上一页')]")));
        previousButton.click();
        
        sleep(2000);
        
        // 验证页码是否回到第一页
        WebElement pageInput = driver.findElement(By.id("pageInput"));
        String pageValue = pageInput.getAttribute("value");
        assertEquals("1", pageValue, "页码应该回到第一页");
    }
    
    @Test
    public void testActivityList_Pagination_FirstPage() {
        // 测试第一页点击上一页
        driver.get(baseUrl + "/admin.html");
        sleep(2000);
        
        driver.switchTo().frame(driver.findElement(By.id("contentFrame")));
        sleep(2000);
        
        // 确保在第一页,点击上一页
        WebElement previousButton = wait.until(ExpectedConditions.elementToBeClickable(
            By.xpath("//button[contains(text(), '上一页')]")));
        previousButton.click();
        
        sleep(1000);
        
        // 验证是否显示提示(通过alert)
        try {
            driver.switchTo().alert();
            String alertText = driver.switchTo().alert().getText();
            assertTrue(alertText.contains("第一页") || alertText.contains("已经是"), 
                "应该显示已经是第一页的提示");
            driver.switchTo().alert().accept();
        } catch (Exception e) {
            // 如果没有alert,可能通过其他方式提示
            assertTrue(true, "应该显示提示信息");
        }
    }
    
    @Test
    public void testCreateActivity_Valid() {
        // 测试创建活动 - 正确信息
        driver.get(baseUrl + "/admin.html");
        sleep(2000);
        
        // 点击新建活动链接
        WebElement createActivityLink = wait.until(ExpectedConditions.elementToBeClickable(
            By.id("createActivity")));
        createActivityLink.click();
        
        sleep(2000);
        
        // 切换到iframe
        driver.switchTo().frame(driver.findElement(By.id("contentFrame")));
        sleep(2000);
        
        // 填写活动名称
        WebElement activityNameInput = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("activityName")));
        activityNameInput.clear();
        activityNameInput.sendKeys("测试活动_" + System.currentTimeMillis());
        
        // 填写活动描述
        WebElement descriptionInput = driver.findElement(By.id("description"));
        descriptionInput.clear();
        descriptionInput.sendKeys("这是一个测试活动描述");
        
        // 点击圈选奖品按钮
        WebElement selectPrizesButton = driver.findElement(By.id("buttonPrizes"));
        selectPrizesButton.click();
        
        sleep(1000);
        
        // 在奖品模态框中选择奖品
        wait.until(ExpectedConditions.presenceOfElementLocated(By.id("prizesModal")));
        List<WebElement> prizeCheckboxes = driver.findElements(
            By.cssSelector("#prizesContainer input[type='checkbox']"));
        
        if (!prizeCheckboxes.isEmpty()) {
            // 选择第一个奖品
            prizeCheckboxes.get(0).click();
            
            // 点击确定按钮
            WebElement confirmButton = driver.findElement(
                By.xpath("//div[@id='prizesModal']//button[contains(text(), '确定')]"));
            confirmButton.click();
            
            sleep(1000);
        }
        
        // 点击圈选用户按钮
        WebElement selectUsersButton = driver.findElement(By.id("buttonUsers"));
        selectUsersButton.click();
        
        sleep(1000);
        
        // 在用户模态框中选择用户
        wait.until(ExpectedConditions.presenceOfElementLocated(By.id("usersModal")));
        List<WebElement> userCheckboxes = driver.findElements(
            By.cssSelector("#usersContainer input[type='checkbox']"));
        
        if (!userCheckboxes.isEmpty()) {
            // 选择第一个用户
            userCheckboxes.get(0).click();
            
            // 点击确定按钮
            WebElement confirmButton = driver.findElement(
                By.xpath("//div[@id='usersModal']//button[contains(text(), '确定')]"));
            confirmButton.click();
            
            sleep(1000);
        }
        
        // 点击创建活动按钮
        WebElement createButton = driver.findElement(By.id("createActivity"));
        createButton.click();
        
        sleep(2000);
        
        // 验证是否显示成功提示(通过alert)
        try {
            driver.switchTo().alert();
            String alertText = driver.switchTo().alert().getText();
            assertTrue(alertText.contains("成功"), "应该显示创建成功提示");
            driver.switchTo().alert().accept();
        } catch (Exception e) {
            // 如果没有alert,检查页面跳转
            assertTrue(true, "活动应该创建成功");
        }
    }
    
    @Test
    public void testCreateActivity_EmptyFields() {
        // 测试创建活动 - 不填任何信息
        driver.get(baseUrl + "/admin.html");
        sleep(2000);
        
        // 点击新建活动链接
        WebElement createActivityLink = wait.until(ExpectedConditions.elementToBeClickable(
            By.id("createActivity")));
        createActivityLink.click();
        
        sleep(2000);
        
        // 切换到iframe
        driver.switchTo().frame(driver.findElement(By.id("contentFrame")));
        sleep(2000);
        
        // 直接点击创建活动按钮,不填写任何信息
        WebElement createButton = wait.until(ExpectedConditions.elementToBeClickable(By.id("createActivity")));
        createButton.click();
        
        sleep(1000);
        
        // 验证是否显示验证错误
        WebElement activityNameInput = driver.findElement(By.id("activityName"));
        String validationMessage = activityNameInput.getAttribute("validationMessage");
        assertNotNull(validationMessage, "应该显示活动名称验证错误");
    }
    
    @Test
    public void testCreateActivity_NoPrizes() {
        // 测试创建活动 - 不选择奖品
        driver.get(baseUrl + "/admin.html");
        sleep(2000);
        
        // 点击新建活动链接
        WebElement createActivityLink = wait.until(ExpectedConditions.elementToBeClickable(
            By.id("createActivity")));
        createActivityLink.click();
        
        sleep(2000);
        
        // 切换到iframe
        driver.switchTo().frame(driver.findElement(By.id("contentFrame")));
        sleep(2000);
        
        // 填写活动名称和描述
        WebElement activityNameInput = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("activityName")));
        activityNameInput.clear();
        activityNameInput.sendKeys("测试活动_" + System.currentTimeMillis());
        
        WebElement descriptionInput = driver.findElement(By.id("description"));
        descriptionInput.clear();
        descriptionInput.sendKeys("这是一个测试活动描述");
        
        // 不选择奖品,直接点击创建
        WebElement createButton = driver.findElement(By.id("createActivity"));
        createButton.click();
        
        sleep(2000);
        
        // 验证是否显示提示(通过alert)
        try {
            driver.switchTo().alert();
            String alertText = driver.switchTo().alert().getText();
            assertTrue(alertText.contains("奖品"), "应该显示请选择奖品的提示");
            driver.switchTo().alert().accept();
        } catch (Exception e) {
            assertTrue(true, "应该显示错误提示");
        }
    }
}
4.2.3奖品页测试

包含以下测试用例:

  • testPrizeList_Display: 测试奖品列表展示
  • testPrizeList_Pagination_Next: 测试翻页-下一页
  • testPrizeList_Pagination_Previous: 测试翻页-上一页
  • testCreatePrize_Valid: 测试创建奖品-正确信息
  • testCreatePrize_EmptyFields: 测试创建奖品-不填信息
    代码如下:
java 复制代码
package com.fgs.demo.selenium;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

/**
 * 奖品页测试类
 * 测试奖品列表、翻页、新建奖品等功能
 */
public class PrizePageTest extends BaseSeleniumTest {
    
    @BeforeEach
    public void login() {
        // 先登录
        driver.get(baseUrl + "/blogin.html");
        
        // 输入登录信息
        WebElement phoneInput = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("loginName")));
        phoneInput.clear();
        phoneInput.sendKeys("17527167018");
        
        WebElement passwordInput = driver.findElement(By.id("password"));
        passwordInput.clear();
        passwordInput.sendKeys("123456");
        
        WebElement loginButton = driver.findElement(By.cssSelector("#loginForm button[type='submit']"));
        loginButton.click();
        
        // 等待登录完成
        sleep(3000);
    }
    
    @Test
    public void testPrizeList_Display() {
        // 测试奖品列表展示
        driver.get(baseUrl + "/admin.html");
        sleep(2000);
        
        // 点击奖品列表链接
        WebElement prizeListLink = wait.until(ExpectedConditions.elementToBeClickable(
            By.xpath("//a[contains(@href, 'prizes-list.html')]")));
        prizeListLink.click();
        
        sleep(2000);
        
        // 切换到iframe
        WebElement iframe = driver.findElement(By.id("contentFrame"));
        driver.switchTo().frame(iframe);
        sleep(2000);
        
        // 验证奖品列表标题
        WebElement title = wait.until(ExpectedConditions.presenceOfElementLocated(By.tagName("h2")));
        assertEquals("奖品列表", title.getText(), "应该显示奖品列表标题");
        
        // 验证是否有奖品项
        List<WebElement> prizeRows = driver.findElements(By.cssSelector("#prizeList tr"));
        assertNotNull(prizeRows, "奖品列表应该存在");
    }
    
    @Test
    public void testPrizeList_Pagination_Next() {
        // 测试翻页 - 下一页
        driver.get(baseUrl + "/admin.html");
        sleep(2000);
        
        // 点击奖品列表链接
        WebElement prizeListLink = wait.until(ExpectedConditions.elementToBeClickable(
            By.xpath("//a[contains(@href, 'prizes-list.html')]")));
        prizeListLink.click();
        
        sleep(2000);
        
        // 切换到iframe
        driver.switchTo().frame(driver.findElement(By.id("contentFrame")));
        sleep(2000);
        
        // 点击下一页按钮
        WebElement nextButton = wait.until(ExpectedConditions.elementToBeClickable(
            By.xpath("//button[contains(text(), '下一页')]")));
        nextButton.click();
        
        sleep(2000);
        
        // 验证页码是否更新
        WebElement pageInput = driver.findElement(By.id("pageInput"));
        String pageValue = pageInput.getAttribute("value");
        assertTrue(Integer.parseInt(pageValue) > 1, "页码应该增加");
    }
    
    @Test
    public void testPrizeList_Pagination_Previous() {
        // 测试翻页 - 上一页
        driver.get(baseUrl + "/admin.html");
        sleep(2000);
        
        // 点击奖品列表链接
        WebElement prizeListLink = wait.until(ExpectedConditions.elementToBeClickable(
            By.xpath("//a[contains(@href, 'prizes-list.html')]")));
        prizeListLink.click();
        
        sleep(2000);
        
        // 切换到iframe
        driver.switchTo().frame(driver.findElement(By.id("contentFrame")));
        sleep(2000);
        
        // 先跳转到第二页
        WebElement nextButton = wait.until(ExpectedConditions.elementToBeClickable(
            By.xpath("//button[contains(text(), '下一页')]")));
        nextButton.click();
        sleep(2000);
        
        // 点击上一页按钮
        WebElement previousButton = wait.until(ExpectedConditions.elementToBeClickable(
            By.xpath("//button[contains(text(), '上一页')]")));
        previousButton.click();
        
        sleep(2000);
        
        // 验证页码是否回到第一页
        WebElement pageInput = driver.findElement(By.id("pageInput"));
        String pageValue = pageInput.getAttribute("value");
        assertEquals("1", pageValue, "页码应该回到第一页");
    }
    
    @Test
    public void testCreatePrize_Valid() {
        // 测试创建奖品 - 正确信息
        driver.get(baseUrl + "/admin.html");
        sleep(2000);
        
        // 点击创建奖品链接
        WebElement createPrizeLink = wait.until(ExpectedConditions.elementToBeClickable(
            By.xpath("//a[contains(@href, 'create-prizes.html')]")));
        createPrizeLink.click();
        
        sleep(2000);
        
        // 切换到iframe
        driver.switchTo().frame(driver.findElement(By.id("contentFrame")));
        sleep(2000);
        
        // 填写奖品名称
        WebElement prizeNameInput = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("prizeName")));
        prizeNameInput.clear();
        prizeNameInput.sendKeys("测试奖品_" + System.currentTimeMillis());
        
        // 填写奖品价格
        WebElement priceInput = driver.findElement(By.id("price"));
        priceInput.clear();
        priceInput.sendKeys("99.99");
        
        // 填写奖品描述
        WebElement descriptionInput = driver.findElement(By.id("description"));
        descriptionInput.clear();
        descriptionInput.sendKeys("这是一个测试奖品描述");
        
        // 上传图片(这里需要准备一个测试图片文件)
        // 注意:实际测试时需要提供一个真实的图片文件路径
        // WebElement imageInput = driver.findElement(By.id("prizeImageUrl"));
        // imageInput.sendKeys("path/to/test/image.jpg");
        
        // 点击创建奖品按钮
        WebElement createButton = driver.findElement(By.cssSelector("button[type='submit']"));
        createButton.click();
        
        sleep(2000);
        
        // 验证是否显示错误提示(因为没有上传图片)
        // 或者如果图片是可选的,验证是否创建成功
        WebElement errorMessage = driver.findElement(By.id("prizeImageUrl-error"));
        if (errorMessage.isDisplayed()) {
            assertTrue(errorMessage.getText().contains("图片"), "应该显示图片错误提示");
        }
    }
    
    @Test
    public void testCreatePrize_EmptyFields() {
        // 测试创建奖品 - 不填信息
        driver.get(baseUrl + "/admin.html");
        sleep(2000);
        
        // 点击创建奖品链接
        WebElement createPrizeLink = wait.until(ExpectedConditions.elementToBeClickable(
            By.xpath("//a[contains(@href, 'create-prizes.html')]")));
        createPrizeLink.click();
        
        sleep(2000);
        
        // 切换到iframe
        driver.switchTo().frame(driver.findElement(By.id("contentFrame")));
        sleep(2000);
        
        // 直接点击创建按钮,不填写任何信息
        WebElement createButton = wait.until(ExpectedConditions.elementToBeClickable(
            By.cssSelector("button[type='submit']")));
        createButton.click();
        
        sleep(1000);
        
        // 验证是否显示验证错误
        WebElement prizeNameInput = driver.findElement(By.id("prizeName"));
        String validationMessage = prizeNameInput.getAttribute("validationMessage");
        assertNotNull(validationMessage, "应该显示奖品名称验证错误");
    }
}
4.2.4用户页测试

包含以下测试用例:

  • testUserList_Display: 测试用户列表展示
  • testRegisterUser_Valid: 测试注册用户-正确信息
  • testRegisterUser_EmptyFields: 测试注册用户-不填信息
  • testRegisterUser_InvalidEmail: 测试注册用户-邮箱格式错误
    代码如下:
java 复制代码
package com.fgs.demo.selenium;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

/**
 * 用户页测试类
 * 测试用户列表、新增用户等功能
 */
public class UserPageTest extends BaseSeleniumTest {
    
    @BeforeEach
    public void login() {
        // 先登录
        driver.get(baseUrl + "/blogin.html");
        
        // 输入登录信息
        WebElement phoneInput = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("loginName")));
        phoneInput.clear();
        phoneInput.sendKeys("17527167018");
        
        WebElement passwordInput = driver.findElement(By.id("password"));
        passwordInput.clear();
        passwordInput.sendKeys("123456");
        
        WebElement loginButton = driver.findElement(By.cssSelector("#loginForm button[type='submit']"));
        loginButton.click();
        
        // 等待登录完成
        sleep(3000);
    }
    
    @Test
    public void testUserList_Display() {
        // 测试用户列表展示
        driver.get(baseUrl + "/admin.html");
        sleep(2000);
        
        // 点击用户列表链接
        WebElement userListLink = wait.until(ExpectedConditions.elementToBeClickable(
            By.id("userList")));
        userListLink.click();
        
        sleep(2000);
        
        // 切换到iframe
        WebElement iframe = driver.findElement(By.id("contentFrame"));
        driver.switchTo().frame(iframe);
        sleep(2000);
        
        // 验证用户列表标题
        WebElement title = wait.until(ExpectedConditions.presenceOfElementLocated(By.tagName("h2")));
        assertEquals("用户列表", title.getText(), "应该显示用户列表标题");
        
        // 验证是否有用户项
        List<WebElement> userRows = driver.findElements(By.cssSelector("#userList tr"));
        assertNotNull(userRows, "用户列表应该存在");
    }
    
    @Test
    public void testRegisterUser_Valid() {
        // 测试注册用户 - 正确信息
        driver.get(baseUrl + "/admin.html");
        sleep(2000);
        
        // 点击注册用户链接
        WebElement registerLink = wait.until(ExpectedConditions.elementToBeClickable(
            By.id("register")));
        registerLink.click();
        
        sleep(2000);
        
        // 切换到iframe
        driver.switchTo().frame(driver.findElement(By.id("contentFrame")));
        sleep(2000);
        
        // 填写用户信息
        WebElement nameInput = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("name")));
        nameInput.clear();
        nameInput.sendKeys("测试用户_" + System.currentTimeMillis());
        
        WebElement mailInput = driver.findElement(By.id("mail"));
        mailInput.clear();
        mailInput.sendKeys("test" + System.currentTimeMillis() + "@qq.com");
        
        WebElement phoneInput = driver.findElement(By.id("phoneNumber"));
        phoneInput.clear();
        phoneInput.sendKeys("138" + System.currentTimeMillis() % 100000000);
        
        // 注意:根据register.html的逻辑,如果admin=false,密码框会被隐藏
        // 这里假设是管理员注册,需要密码
        WebElement passwordInput = driver.findElement(By.id("password"));
        if (passwordInput.isDisplayed()) {
            passwordInput.clear();
            passwordInput.sendKeys("123456");
        }
        
        // 点击注册按钮
        WebElement registerButton = driver.findElement(By.cssSelector("button[type='submit']"));
        registerButton.click();
        
        sleep(2000);
        
        // 验证是否显示成功提示(通过alert)
        try {
            driver.switchTo().alert();
            String alertText = driver.switchTo().alert().getText();
            assertTrue(alertText.contains("成功"), "应该显示注册成功提示");
            driver.switchTo().alert().accept();
        } catch (Exception e) {
            // 如果没有alert,检查页面跳转
            assertTrue(true, "用户应该注册成功");
        }
    }
    
    @Test
    public void testRegisterUser_EmptyFields() {
        // 测试注册用户 - 不填信息
        driver.get(baseUrl + "/admin.html");
        sleep(2000);
        
        // 点击注册用户链接
        WebElement registerLink = wait.until(ExpectedConditions.elementToBeClickable(
            By.id("register")));
        registerLink.click();
        
        sleep(2000);
        
        // 切换到iframe
        driver.switchTo().frame(driver.findElement(By.id("contentFrame")));
        sleep(2000);
        
        // 直接点击注册按钮,不填写任何信息
        WebElement registerButton = wait.until(ExpectedConditions.elementToBeClickable(
            By.cssSelector("button[type='submit']")));
        registerButton.click();
        
        sleep(1000);
        
        // 验证是否显示验证错误
        WebElement nameInput = driver.findElement(By.id("name"));
        String validationMessage = nameInput.getAttribute("validationMessage");
        assertNotNull(validationMessage, "应该显示姓名验证错误");
    }
    
    @Test
    public void testRegisterUser_InvalidEmail() {
        // 测试注册用户 - 邮箱格式错误
        driver.get(baseUrl + "/admin.html");
        sleep(2000);
        
        // 点击注册用户链接
        WebElement registerLink = wait.until(ExpectedConditions.elementToBeClickable(
            By.id("register")));
        registerLink.click();
        
        sleep(2000);
        
        // 切换到iframe
        driver.switchTo().frame(driver.findElement(By.id("contentFrame")));
        sleep(2000);
        
        // 填写信息,但邮箱格式错误
        WebElement nameInput = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("name")));
        nameInput.clear();
        nameInput.sendKeys("测试用户");
        
        WebElement mailInput = driver.findElement(By.id("mail"));
        mailInput.clear();
        mailInput.sendKeys("invalid-email");
        
        WebElement phoneInput = driver.findElement(By.id("phoneNumber"));
        phoneInput.clear();
        phoneInput.sendKeys("13800138000");
        
        // 点击注册按钮
        WebElement registerButton = driver.findElement(By.cssSelector("button[type='submit']"));
        registerButton.click();
        
        sleep(1000);
        
        // 验证是否显示邮箱格式错误
        String validationMessage = mailInput.getAttribute("validationMessage");
        assertNotNull(validationMessage, "应该显示邮箱格式验证错误");
    }
}
4.2.5抽奖页测试

包含以下测试用例:

  • testDrawPage_Display: 测试抽奖页面显示
  • testDrawPage_StartDraw: 测试开始抽奖
  • testDrawPage_ViewWinningRecords: 测试查看中奖名单
  • testDrawPage_ShareResult: 测试分享抽奖结果
    代码如下:
java 复制代码
package com.fgs.demo.selenium;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;

import static org.junit.jupiter.api.Assertions.*;

/**
 * 抽奖页测试类
 * 测试抽奖功能和中奖名单查看
 */
public class DrawPageTest extends BaseSeleniumTest {
    
    @BeforeEach
    public void login() {
        // 先登录
        driver.get(baseUrl + "/blogin.html");
        
        // 输入登录信息
        WebElement phoneInput = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("loginName")));
        phoneInput.clear();
        phoneInput.sendKeys("17527167018");
        
        WebElement passwordInput = driver.findElement(By.id("password"));
        passwordInput.clear();
        passwordInput.sendKeys("123456");
        
        WebElement loginButton = driver.findElement(By.cssSelector("#loginForm button[type='submit']"));
        loginButton.click();
        
        // 等待登录完成
        sleep(3000);
    }
    
    @Test
    public void testDrawPage_Display() {
        // 测试抽奖页面显示
        String activityId = "11";
        String activityName = "天佑之子";
        String valid = "true";
        
        driver.get(baseUrl + "/draw.html?activityId=" + activityId 
            + "&activityName=" + activityName + "&valid=" + valid);
        
        sleep(3000);
        
        // 验证页面标题
        WebElement title = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("title")));
        assertNotNull(title.getText(), "应该显示活动名称");
        
        // 验证是否有抽奖按钮
        WebElement nextButton = wait.until(ExpectedConditions.presenceOfElementLocated(
            By.cssSelector(".btn.next-btn")));
        assertNotNull(nextButton, "应该显示开始抽奖按钮");
    }
    
    @Test
    public void testDrawPage_StartDraw() {
        // 测试开始抽奖
        String activityId = "12"; //
        String activityName = "自动化测试活动";
        String valid = "true";
        
        driver.get(baseUrl + "/draw.html?activityId=" + activityId 
            + "&activityName=" + activityName + "&valid=" + valid);
        
        sleep(3000);
        
        // 点击开始抽奖按钮
        WebElement nextButton = wait.until(ExpectedConditions.elementToBeClickable(
            By.cssSelector(".btn.next-btn")));
        nextButton.click();
        
        sleep(2000);
        
        // 验证页面状态变化(显示奖品信息或闪烁效果)
        WebElement disc = driver.findElement(By.id("disc"));
        assertNotNull(disc.getText(), "应该显示奖品信息");
    }
    
    @Test
    public void testDrawPage_ViewWinningRecords() {
        String activityId = "11";
        String activityName = "天佑之子";
        String valid = "false"; // 活动已完成
        
        driver.get(baseUrl + "/draw.html?activityId=" + activityId 
            + "&activityName=" + activityName + "&valid=" + valid);
        
        sleep(3000);
        
        // 验证是否显示中奖名单
        WebElement disc = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("disc")));
        String discText = disc.getText();
        assertTrue(discText.contains("中奖名单") || discText.contains("名单"), 
            "应该显示中奖名单标题");
        
        // 验证是否有中奖记录列表
        WebElement list = driver.findElement(By.id("list"));
        assertNotNull(list, "应该显示中奖记录列表");
    }
    
    @Test
    public void testDrawPage_ShareResult() {
        String activityId = "11";
        String activityName = "天佑之子";
        String valid = "false"; // 活动已完成
        
        driver.get(baseUrl + "/draw.html?activityId=" + activityId 
            + "&activityName=" + activityName + "&valid=" + valid);
        
        sleep(3000);
        
        // 等待分享按钮出现
        WebElement shareButton = wait.until(ExpectedConditions.elementToBeClickable(
            By.cssSelector(".btn.copy-btn")));
        
        // 点击分享按钮
        shareButton.click();
        
        sleep(1000);
        
        // 验证是否显示复制成功提示(通过alert)
        try {
            driver.switchTo().alert();
            String alertText = driver.switchTo().alert().getText();
            assertTrue(alertText.contains("复制") || alertText.contains("剪贴板"), 
                "应该显示链接已复制的提示");
            driver.switchTo().alert().accept();
        } catch (Exception e) {
            // 如果没有alert,可能通过其他方式提示
            assertTrue(true, "应该显示分享成功提示");
        }
    }

5.性能测试

5.1接口测试

5.1.1登录页接口测试
5.1.1.1 密码登录接口测试
5.1.1.2 发送验证码接口测试
5.1.1.3验证码登录接口测试
5.1.2活动页接口测试
5.1.2.1创建活动接口测试
5.1.2.2创建活动接口测试
5.1.2.3创建活动接口测试
5.1.3用户页接口测试
5.1.4奖品页接口测试

安全性测试

  • 当前未执行安全性测试。建议检查:
    • 鉴权与会话:JWT token 有效期、过期与伪造校验;登录错误次数限制;验证码暴力破解防护。
    • 输入与存储:参数校验绕过、SQL 注入、XSS;敏感配置(DB/SMTP 密码)外置化与加密。
    • 传输与接口:HTTPS/HTTP 限制,敏感接口权限(活动/奖品/用户 CRUD、抽奖操作)。
    • 审计与日志:关键操作日志留存,异常不泄露敏感信息。

缺陷列表

BUG-LOTTERY-001

  • 严重程度: P2
  • 缺陷描述: 活动列表展示应该首先展示未结束的抽奖活动 方便用户参与抽奖 而不是未完结和已结束活动混合展示 单纯按照创建时间排序
  • 复现步骤:
  1. 管理员切换至活动管理页面
  2. 管理员点击活动列表
  • 状态: 已修复
  • 备注 : 修复前:
  • 修复后:

BUG-LOTTERY-002

  • 严重程度: P2
  • 缺陷描述: 普通用户注册未对用户名称进行重复检查 导致注册普通用户姓名信息可以相同
  • 复现步骤:
  1. 管理员切换至用户管理页面
  2. 管理员点击注册用户
  3. 填写用户信息 姓名信息填写为已有姓名
  4. 点击注册按钮
  • 状态: 已修复
  • 备注 :
    修复前:

    修复后:

BUG-LOTTERY-003

  • 严重程度: P1
  • 缺陷描述: 抽奖结果信息展示有误
  • 复现步骤:
  1. 管理员切换至活动管理页面
  2. 管理员点击活动列表
  3. 点击已结束活动 查看抽奖结果
  • 状态: 已修复
  • 备注 :
    这是前端问题。
    前端代码在 draw.html 第172行使用了 records[i].winnerName
    后端返回的字段名是 winningName(不是 winnerName)
    因为字段名不匹配 导致显示时出现 "undefined"
    修复后:
相关推荐
TT哇2 小时前
【Database Navigator 插件】idea 社区版连接 mysql 数据库
java·数据库·mysql·intellij-idea·database
做人不要太理性2 小时前
【Linux系统】ELF 文件格式的硬核揭秘
java·linux·服务器
zhglhy2 小时前
Jaccard相似度算法原理及Java实现
java·开发语言·算法
啥都不懂的小小白2 小时前
Java日志篇3:Logback 配置全解析与生产环境最佳实践
java·开发语言·logback
江沉晚呤时2 小时前
延迟加载(Lazy Loading)详解及在 C# 中的应用
java·开发语言·microsoft·c#
谷哥的小弟2 小时前
Spring Framework源码解析——ConfigurableApplicationContext
java·spring·源码
麒qiqi3 小时前
【Linux 系统编程】文件 IO 与 Makefile 核心实战:从系统调用到工程编译
java·前端·spring
en-route3 小时前
Spring 框架下 Redis 会话存储应用实践
java·redis·spring
JIngJaneIL3 小时前
基于Java酒店管理系统(源码+数据库+文档)
java·开发语言·数据库·vue.js·spring boot