目录
项目背景
随着线上营销的开始,越来越多的企业愈加重视通过一些线上的活动来吸引和留住客户。抽奖系统就是其中的营销策略之一,这能够显著提升用户的参与度和曝光率。于是准备开发以抽奖活动为背景的 Spring Boot 项目。
测试范围
测试所有业务模块,其中包括:
人员模块:管理员注册与登录及普通用户的注册
奖品模块:奖品创建、奖品列表的展示
活动模块:活动创建、活动列表展示,活动状态转换
通知模块:邮箱通知
抽奖模块:抽奖动作及抽奖结果展示
测试环境
操作系统:Windows 11
浏览器:chrome、Edge
数据库:MySQL
测试工具:JDK 17、Postman、JMeter、Selenium
测试策略与方法
- 功能测试:采用手动测试功能以及自动化编码测试工具
- 性能测试:JMeter模拟高并发抽奖请求
- 兼容性测试:针对不同系统设备浏览器访问该系统查看是否正常
- 界面测试:手动测试查看页面是否正常显示以及美观程度
测试用例设计

测试结果
功能测试
UI界面测试展示
密码登录页面
测试用例:手机号密码均为空进行登录
预期结果:显示提示词提示用户进行输入

测试用例:其中一项为空进行登录
预期结果:显示提示词提示用户空的输入框进行输入


测试用例:输入错误的手机号与密码
预期结果:弹窗提示用户,重新进行用户信息输入

验证码登录页面
测试用例:手机号验证码均为空
预期结果:显示提示词提示用户进行输入

测试用例:验证码为空
预期结果:显示提示词提示用户输入

测试用例:验证码输入错误
预期结果:弹窗提示用户验证码错误

测试用例:手机号输入错误,错误手机号的用户不存在情况
预期结果:弹窗提示用户不存在

管理员登录前注册页面
测试用例:输入为空
预期结果:显示提示词,提示用户进行信息输入

测试用例:输入邮箱格式错误
预期结果:显示提示词,提示用户输入有效的邮箱

测试用例:密码格式错误(密码字符少于6位)
预期结果:显示提示词提示用户

测试用例:密码格式错误,(包含不支持的字符或密码长度过长)
预期结果:弹窗提示用户密码格式错误
普通用户注册页面
测试用例:输入均为空
预期结果:显示提示词提示用户输入

测试用例:邮箱格式输入错误
预期结果:显示提示词,提示用户输入有效的邮箱格式

测试用例:手机号格式错误
预期结果:弹窗提示手机号错误

人员列表展示页面

奖品创建页面
测试用例:输入全为空
预期结果:弹窗提示创建失败

测试用例:上传大于1M的图片
预期结果:弹窗提示创建失败

奖品列表展示页面

活动创建页面
测试用例:活动名与描述为空
预期结果:显示提示词提示用户输入

测试用例:奖品为空
预期结果:弹窗提示用户输入奖品

测试用例:人员为空
预期结果:弹窗提示用户输入参与活动人员

测试用例:奖品数量大于人员数量
预期结果:弹窗提示奖品人员数量异常

活动列表页面

活动抽奖页面
抽奖流程展示:

名称跳转,点击"点我确定"即可停止

抽完奖品最后进行中奖名单展示:

活动状态由抽奖进行中变为已结束


自动化测试
驱动类
java
package common;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
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.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.Duration;
public class AutoUtils {
public static WebDriver driver=null;
public WebDriverWait wait=null;
public static String detailUrl="http://39.105.181.10:8080/admin.html";
public AutoUtils(String url){
//调用driver对象
driver=createDriver();
driver.get(url);
wait=new WebDriverWait(driver, Duration.ofSeconds(3));
}
/**
* 获取驱动对象
*/
public static WebDriver createDriver(){
if(driver==null){
//下载驱动
// WebDriverManager.chromedriver().setup();
System.setProperty("webdriver.chrome.driver","D:\\selenium\\chromedriver-win64\\chromedriver.exe");
System.setProperty("selenium-manage.disable","true");
//添加配置:允许访问所有的连接
ChromeOptions options=new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
//创建驱动对象
driver=new ChromeDriver(options);
//隐式等待
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
}
return driver;
}
/**
* 屏幕截图
* 屏幕截图文件目录
*
*/
public void ScreenShot(String str) throws IOException {
//年月日
SimpleDateFormat sim1=new SimpleDateFormat("yyyy-MM-dd");
//时分秒
SimpleDateFormat sim2=new SimpleDateFormat("HHmmssSS");
String dirTime=sim1.format(System.currentTimeMillis());
String fileTime=sim2.format(System.currentTimeMillis());
//图片文件名:路径+图片名称
String fileName="./src/test/java/images/"+dirTime+"/"+str+"-"+fileTime+".png";
File srcFile=((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(srcFile,new File(fileName));
}
/**
* 销毁driver对象--关闭浏览器
*/
public static void quit(){
if(driver!=null){
driver.quit();
}
}
}
登录类
java
package tests;
import common.AutoUtils;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import java.io.IOException;
public class BloginPage extends AutoUtils {
public final static String url="http://39.105.181.10:8080/blogin.html";
public BloginPage() {
super(url);
}
/**
* 密码登录流程测试
* @throws IOException
*/
public void passwordLogin() throws IOException, InterruptedException {
checkPasswordBloginPage();
//异常登录:含有空值
blogin("","111111");
blogin("13311111111","");
blogin("13311111111","11111");
//异常登录:输入错误
bloginError("13333333333","111111");
bloginError("10333333333","111111");
bloginError("13311111111","111112");
//正常登录
blogin("13311111111","111111");
}
/**
* 密码登录页面是否能正常打开
*/
public void checkPasswordBloginPage() throws IOException {
waitElement();
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"));
driver.findElement(By.cssSelector("#phoneNumber"));
driver.findElement(By.cssSelector("#password"));
driver.findElement(By.cssSelector("#loginForm > button"));
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"));
}
/**
* 密码登录:异常登录
*/
public void bloginError(String phoneNumber,String password) throws InterruptedException {
clearPasswordLogin();
driver.findElement(By.cssSelector("#phoneNumber")).sendKeys(phoneNumber);
driver.findElement(By.cssSelector("#password")).sendKeys(password);
driver.findElement(By.cssSelector("#loginForm > button")).click();
Thread.sleep(1000);
Alert alert=driver.switchTo().alert();
alert.accept();
}
public void blogin(String phoneNumber,String password){
clearPasswordLogin();
driver.findElement(By.cssSelector("#phoneNumber")).sendKeys(phoneNumber);
driver.findElement(By.cssSelector("#password")).sendKeys(password);
driver.findElement(By.cssSelector("#loginForm > button")).click();
}
/**
* 验证码登录页面是否能正常打开
*/
public void checkCodeBloginPage(){
waitElement();
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"));
driver.findElement(By.cssSelector("#loginMobile"));
driver.findElement(By.cssSelector("#verificationCode"));
driver.findElement(By.cssSelector("#getVerificationCode"));
driver.findElement(By.cssSelector("#codeForm > button"));
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"));
}
/**
* 验证码登录:异常登录
*/
public void codeBloginError(String phoneNumber,String code){
clearCodeLogin();
driver.findElement(By.cssSelector("#phoneNumber")).sendKeys(phoneNumber);
driver.findElement(By.cssSelector("#codeForm > button")).click();
driver.findElement(By.cssSelector("#verificationCode")).sendKeys(code);
driver.findElement(By.cssSelector("#loginForm > button")).click();
Alert alert=driver.switchTo().alert();
alert.accept();
}
public void codeBlogin(String phoneNumber,String code){
clearCodeLogin();
driver.findElement(By.cssSelector("#phoneNumber")).sendKeys(phoneNumber);
driver.findElement(By.cssSelector("#codeForm > button")).click();
driver.findElement(By.cssSelector("#verificationCode")).sendKeys(code);
driver.findElement(By.cssSelector("#loginForm > button")).click();
}
/**
* 密码登录输入框清空
*/
public void clearPasswordLogin(){
driver.findElement(By.cssSelector("#phoneNumber")).clear();
driver.findElement(By.cssSelector("#password")).clear();
}
/**
* 验证码输入框清空
*/
public void clearCodeLogin(){
driver.findElement(By.cssSelector("#phoneNumber")).clear();
driver.findElement(By.cssSelector("#verificationCode")).clear();
}
/**
* 等待页面元素加载完成
*/
public void waitElement(){
wait.until(webDriver ->{
JavascriptExecutor js = (JavascriptExecutor) webDriver;
return "complete".equals(js.executeScript("return document.readyState"));
});
}
}
注册类
java
package tests;
import common.AutoUtils;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import java.io.IOException;
/**
* 登录前的注册功能:管理员注册
*/
public class RegisterPage extends AutoUtils {
public static String url="http://39.105.181.10:8080/register.html?admin=true";
public RegisterPage() {
super(url);
}
public void register() throws IOException, InterruptedException {
//检查元素是否正确显示
checkPageRight();
//含空值注册
register("","120000@qq.com","13311111111","111111");
register("testName","","13311111111","111111");
register("testName","120000@qq.com","","111111");
register("testName","120000@qq.com","13311111111","");
//密码长度少于6
register("testName","120000@qq.com","13311111111","1111");
//错误格式注册
register("testName","@qq.com","13311111111","111111");
register("testName","120000qq.com","13311111111","111111");
register("testName","120000@.com","13311111111","111111");
register("testName","120000@qq.","13311111111","111111");
register("testName","120000@qq.c","13311111111","111111");
registerErrorExp("testName","120000@qq.com","133111111","111111");
registerErrorExp("testName","120000@qq.com","10311111111","111111");
registerErrorExp("testName","120000@qq.com","13311111111","11111111@");
//正常注册
registerNormal("testName","120000@qq.com","13311111111","111111");
}
private void registerNormal(String name,String mail,String phoneNumber,String password) throws InterruptedException {
clearRegister();
driver.findElement(By.cssSelector("#name")).sendKeys(name);
driver.findElement(By.cssSelector("#mail")).sendKeys(mail);
driver.findElement(By.cssSelector("#phoneNumber")).sendKeys(phoneNumber);
driver.findElement(By.cssSelector("#password")).sendKeys(password);
driver.findElement(By.cssSelector("#registerForm > button")).click();
Thread.sleep(1000);
Alert alert=driver.switchTo().alert();
alert.accept();
}
/**
* 注册页面可以正常打开
*/
public void checkPageRight() throws IOException {
waitElement();
//检查注册框
driver.findElement(By.cssSelector("#name"));
driver.findElement(By.cssSelector("#mail"));
driver.findElement(By.cssSelector("#phoneNumber"));
driver.findElement(By.cssSelector("#password"));
String button=driver.findElement(By.cssSelector("#registerForm > button")).getText();
assert (!button.equals("注册"));
//进行元素检查后截图并保存(以方法名命名截图)
ScreenShot(Thread.currentThread().getStackTrace()[1].getMethodName());
}
/**
* 管理员注册:有空值/正常注册
*/
public void register(String name,String mail,String phoneNumber,String password){
clearRegister();
driver.findElement(By.cssSelector("#mail")).sendKeys(mail);
driver.findElement(By.cssSelector("#phoneNumber")).sendKeys(phoneNumber);
driver.findElement(By.cssSelector("#password")).sendKeys(password);
driver.findElement(By.cssSelector("#registerForm > button")).click();
}
/**
* 异常注册:有弹窗
* @param name
* @param mail
* @param phoneNumber
* @param password
*/
public void registerErrorExp(String name,String mail,String phoneNumber,String password) throws InterruptedException {
clearRegister();
driver.findElement(By.cssSelector("#name")).sendKeys(name);
driver.findElement(By.cssSelector("#mail")).sendKeys(mail);
driver.findElement(By.cssSelector("#phoneNumber")).sendKeys(phoneNumber);
driver.findElement(By.cssSelector("#password")).sendKeys(password);
driver.findElement(By.cssSelector("#registerForm > button")).click();
Thread.sleep(1000);
Alert alert=driver.switchTo().alert();
alert.accept();
}
/**
* 输入框清空
*/
public void clearRegister(){
driver.findElement(By.cssSelector("#name")).clear();
driver.findElement(By.cssSelector("#mail")).clear();
driver.findElement(By.cssSelector("#phoneNumber")).clear();
driver.findElement(By.cssSelector("#password")).clear();
}
/**
* 等待元素的加载
*/
public void waitElement() {
wait.until(webDriver -> {
JavascriptExecutor js = (JavascriptExecutor) webDriver;
return "complete".equals(js.executeScript("return document.readyState"));
});
}
}
活动中心类
java
package tests;
import common.AutoUtils;
import org.openqa.selenium.*;
import java.io.IOException;
public class AdminPage extends AutoUtils {
public static String url = "http://39.105.181.10:8080/admin.html";
public AdminPage() {
super(url);
}
/**
* 检查页面元素
*/
public void checkAdminPage() throws IOException, InterruptedException {
//测试人员模块
checkUserRegister();
//测试奖品模块
checkPrize();
//测试活动模块
checkActivity();
}
private void checkActivity() throws IOException, InterruptedException {
waitElement();
driver.findElement(By.cssSelector("#createActivity")).click();
checkActivityPage();
//异常创建
createActivityExc("","测试1","奖品1","人员");
createActivityExc("测试活动1","","奖品1","人员");
createActivityExc("测试活动1","测试1","","人员");
createActivityExc("测试活动1","测试1","奖品1","");
//正常创建
createActivity("测试活动1","测试1","奖品1","人员");
driver.switchTo().defaultContent();
}
public void createActivityExc(String name,String description,String prize,String user) throws InterruptedException {
clearActivity();
driver.findElement(By.cssSelector("#activityName")).sendKeys(name);
driver.findElement(By.cssSelector("#description")).sendKeys(description);
if(!prize.isEmpty()){
driver.findElement(By.cssSelector("#buttonPrizes")).click();
driver.findElement(By.cssSelector("#prize-18")).click();
driver.findElement(By.cssSelector("#prizesModal > div > div.form-btn-box > button.btn.btn-primary")).click();
}
if(!user.isEmpty()){
driver.findElement(By.cssSelector("#buttonUsers")).click();
driver.findElement(By.cssSelector("#user-40")).click();
driver.findElement(By.cssSelector("#usersModal > div > div.form-btn-box > button.btn.btn-primary")).click();
}
driver.findElement(By.cssSelector("#createActivity")).click();
//当活动名称与描述已填写,而人员或者奖品未填写时
if(name!=""&&description!=""){
if(prize==""||user==""){
Thread.sleep(1000);
Alert alert=driver.switchTo().alert();
alert.accept();
}
}
}
/**
* 正常创建活动
*/
public void createActivity(String name,String description,String prize,String user) throws InterruptedException {
clearActivity();
driver.findElement(By.cssSelector("#activityName")).sendKeys(name);
driver.findElement(By.cssSelector("#description")).sendKeys(description);
if(!prize.isEmpty()){
driver.findElement(By.cssSelector("#buttonPrizes")).click();
driver.findElement(By.cssSelector("#prize-18")).click();
driver.findElement(By.cssSelector("#prizesModal > div > div.form-btn-box > button.btn.btn-primary")).click();
}
if(!user.isEmpty()){
driver.findElement(By.cssSelector("#buttonUsers")).click();
driver.findElement(By.cssSelector("#user-40")).click();
driver.findElement(By.cssSelector("#usersModal > div > div.form-btn-box > button.btn.btn-primary")).click();
}
driver.findElement(By.cssSelector("#createActivity")).click();
Thread.sleep(1000);
Alert alert=driver.switchTo().alert();
alert.accept();
}
/**
* 清除输入内容
*/
public void clearActivity(){
driver.findElement(By.cssSelector("#activityName")).clear();
driver.findElement(By.cssSelector("#description")).clear();
String prizeText=driver.findElement(By.cssSelector("#buttonPrizes")).getText();
if(prizeText.equals("圈选奖品(已选)")){
driver.findElement(By.cssSelector("#buttonPrizes")).click();
driver.findElement(By.cssSelector("#prize-18")).click();
driver.findElement(By.cssSelector("#prizesModal > div > div.form-btn-box > button.btn.btn-primary")).click();
}
String userText=driver.findElement(By.cssSelector("#buttonUsers")).getText();
if(prizeText.equals("圈选人员(已选)")){
driver.findElement(By.cssSelector("#buttonUsers")).click();
driver.findElement(By.cssSelector("#user-40")).click();
driver.findElement(By.cssSelector("#usersModal > div > div.form-btn-box > button.btn.btn-primary")).click();
}
}
public void checkActivityPage() throws IOException {
driver.switchTo().frame("contentFrame");
driver.findElement(By.cssSelector("#activityName"));
driver.findElement(By.cssSelector("#description"));
driver.findElement(By.cssSelector("#buttonPrizes"));
driver.findElement(By.cssSelector("#buttonUsers"));
driver.findElement(By.cssSelector("#createActivity"));
String createPrize=driver.findElement(By.cssSelector("#buttonPrizes")).getText();
String createUser=driver.findElement(By.cssSelector("#buttonUsers")).getText();
String create=driver.findElement(By.cssSelector("#createActivity")).getText();
assert (!createPrize.equals("圈选奖品"));
assert (!createUser.equals("圈选人员"));
assert (!create.equals("创建活动"));
ScreenShot(Thread.currentThread().getStackTrace()[1].getMethodName());
}
private void checkPrize() throws IOException, InterruptedException {
waitElement();
//奖品列表展示
driver.findElement(By.cssSelector("body > div.cont-box > div.sidebar > ul > li:nth-child(2) > ul > li:nth-child(1) > a")).click();
driver.findElement(By.cssSelector("body > div.cont-box > div.sidebar > ul > li:nth-child(2) > ul > li:nth-child(2) > a")).click();
waitElement();
checkCreatePrizePage();
//空值创建
createPrizeNull("","D://PIC//1dfc13b4-2458-4c5a-9f1e-0e9f606c06fd.png","","");
createPrizeNull("testprize","","","");
createPrizeNull("","","","testdescription");
createPrizeNull("","","29.9","");
//正常创建
createPrize("testprize","D://PIC//1dfc13b4-2458-4c5a-9f1e-0e9f606c06fd.png","29.9","testdescription");
Thread.sleep(1000);
Alert alert=driver.switchTo().alert();
alert.accept();
}
//检查页面元素是否存在
public void checkCreatePrizePage() throws IOException {
waitElement();
driver.switchTo().frame("contentFrame");
driver.findElement(By.cssSelector("#prizeName"));
driver.findElement(By.cssSelector("#prizeImageUrl"));
driver.findElement(By.cssSelector("#price"));
driver.findElement(By.cssSelector("#description"));
driver.findElement(By.cssSelector("body > div > button"));
ScreenShot(Thread.currentThread().getStackTrace()[1].getMethodName());
}
/**
* 创建奖品包含空值
* @param prizeName
* @param imageUrl
* @param price
* @param description
*/
public void createPrizeNull(String prizeName,String imageUrl,String price,String description) throws InterruptedException {
clearPrize();
driver.findElement(By.cssSelector("#prizeName")).sendKeys(prizeName);
if(imageUrl!=""){
driver.findElement(By.cssSelector("#prizeImageUrl")).sendKeys(imageUrl);
}
driver.findElement(By.cssSelector("#price")).sendKeys(price);
driver.findElement(By.cssSelector("#description")).sendKeys(description);
driver.findElement(By.cssSelector("body > div > button")).click();
Thread.sleep(1000);
Alert alert=driver.switchTo().alert();
alert.accept();
}
public void createPrize(String prizeName,String imageUrl,String price,String description){
clearPrize();
driver.findElement(By.cssSelector("#prizeName")).sendKeys(prizeName);
if(imageUrl!=""){
driver.findElement(By.cssSelector("#prizeImageUrl")).sendKeys(imageUrl);
}
driver.findElement(By.cssSelector("#price")).sendKeys(price);
driver.findElement(By.cssSelector("#description")).sendKeys(description);
driver.findElement(By.cssSelector("body > div > button")).click();
}
public void clearPrize(){
driver.findElement(By.cssSelector("#prizeName")).clear();
driver.findElement(By.cssSelector("#prizeImageUrl")).clear();
driver.findElement(By.cssSelector("#price")).clear();
driver.findElement(By.cssSelector("#description")).clear();
}
/**
* 普通用户注册过程
*/
private void checkUserRegister() throws IOException, InterruptedException {
waitElement();
//用户列表展示
driver.findElement(By.cssSelector("#userList")).click();
driver.findElement(By.cssSelector("#register")).click();
waitElement();
checkAfterRegisterPage();
//空值注册
register("","123450@qq.com","13245678901");
register("testName","","13245678901");
register("testName","123450@qq.com","");
//错误注册:手机号错误
alterRegister("testName","123450@qq.com","10123456789");
alterRegister("testName","123450@qq.com","131234567");
alterRegister("testName","123450@qq.com","1312345678999");
//正常注册
register("testName","123450@qq.com","13245678901");
}
//检查普通用户注册元素
public void checkAfterRegisterPage() throws IOException {
waitElement();
driver.switchTo().frame("contentFrame");
driver.findElement(By.cssSelector("#name"));
driver.findElement(By.cssSelector("#mail"));
driver.findElement(By.cssSelector("#phoneNumber"));
driver.findElement(By.cssSelector("#registerForm > button"));
String register=driver.findElement(By.cssSelector("#registerForm > button")).getText();
assert !register.equals("注册");
ScreenShot(Thread.currentThread().getStackTrace()[1].getMethodName());
}
/**
* 异常注册:手机号错误
* @param name
*/
public void alterRegister(String name,String mail,String phoneNumber) throws InterruptedException {
clearUser();
driver.findElement(By.cssSelector("#name")).sendKeys(name);
driver.findElement(By.cssSelector("#mail")).sendKeys(mail);
driver.findElement(By.cssSelector("#phoneNumber")).sendKeys(phoneNumber);
driver.findElement(By.cssSelector("#registerForm > button")).click();
Thread.sleep(1000);
Alert alert=driver.switchTo().alert();
alert.accept();
}
/**
* 空值注册及正常注册
* @param name
* @param mail
* @param phoneNumber
*/
public void register(String name,String mail,String phoneNumber){
clearUser();
driver.findElement(By.cssSelector("#name")).sendKeys(name);
driver.findElement(By.cssSelector("#mail")).sendKeys(mail);
driver.findElement(By.cssSelector("#phoneNumber")).sendKeys(phoneNumber);
driver.findElement(By.cssSelector("#registerForm > button")).click();
}
public void clearUser(){
waitElement();
driver.findElement(By.cssSelector("#name")).clear();
driver.findElement(By.cssSelector("#mail")).clear();
driver.findElement(By.cssSelector("#phoneNumber")).clear();
}
/**
* 等待元素的加载
*/
public void waitElement() {
wait.until(webDriver -> {
JavascriptExecutor js = (JavascriptExecutor) webDriver;
return "complete".equals(js.executeScript("return document.readyState"));
});
}
}
性能测试
接口测试
管理员注册接口:

管理员登录接口:

查看活动列表接口:

查看人员列表接口:

查看奖品列表接口:

注册普通用户接口:

创建奖品接口:

创建活动接口:

负载测试
聚合报告

TPS

响应时间

性能测试报告


兼容性测试
电脑谷歌浏览器:

电脑Edge浏览器:

苹果手机浏览器:

安卓手机浏览器:

测试总结
部分页面关于错误提示不清晰,有待改进
