一. 项目背景
创意论坛系统是采用前后端分离的方式实现的,使用到的技术有:SpringBoot,SpringMVC,MyBatis,MySQL。
该系统旨在为用户提供一个基于 Web 的文章发布和讨论平台。用户可以进行注册登录、查看和修改个人信息,以及进行帖子的增删改查等基础操作。此外,系统还提供了评论、站内信等交流功能,用户可以对帖子进行点赞,并在帖子详情页上查看阅读量、点赞数、评论量等信息。下文是对该系统进行各种测试得出的测试报告。
二. 测试安排
2.1 测试环境
硬件:Nitro AN515-45(R7-5800H/16GB/512GB)
操作系统:Windows 10 家庭中文版
项目运行环境:chrome 128.0.6613.114(正式版本)(64位)、maven、JDK1.8
自动化脚本运行环境:IntelliJ IDEA 2023.3.7 (Ultimate Edition)
2.2 测试用例
2.2.1 功能测试用例
2.2.2 非功能测试用例
三. 测试分类
3.1 部分手动功能测试
3.1.1 对注册功能进行测试
场景1:在输入部分注册信息时,由于信息不全,点击注册按钮后系统应该给出相应的提示。
预期结果:页面提示部分信息不能为空。
实际结果:系统确实给出了相应的提示,要求补全所有必填项,与预期一致。
场景2:输入一个不存在的用户名,并且输入密码与确认密码不一致,然后点击注册按钮。
预期结果:系统应该提示用户检查确认密码是否输入一致。
实际结果:系统确实给出了相应的提示,指示用户检查确认密码,与预期结果一致。
场景3:输入一个已经存在的用户名,并确保密码和确认密码一致,然后点击注册按钮。
预期结果:系统应该提示用户该用户名已经存在。
实际结果:系统确实给出了提示,提示用户该用户名已经存在,与预期结果一致。
场景4:输入一个不存在的用户名,同时确保密码和确认密码一致,然后点击注册按钮。
预期结果:系统应该显示注册成功,并跳转回登录界面。
实际结果:系统确实显示了注册成功,并且跳转回了登录界面,符合预期。
3.1.2 对登录功能进行测试
场景1:用户名与密码不匹配
预期结果:提示出错误
实际结果:提示用户名或密码错误
场景2:密码为空
预期结果:登录失败,提示密码不能为空
实际结果:登录失败,提示密码不能为空,与预期结果一致
场景3:用户名为空
预期结果:登录失败,提示用户名不能为空
实际结果:登录失败,提示用户名不能为空,与预期结果一致
3.1.3 个人中心功能测试
场景1:点击个人中心
预期结果:跳转到用户中心页面,并正确显示当前用户信息
实际结果:跳转成功,并正确显示当前用户信息,与预期结果一致
场景2:修改用户昵称等信息
预期结果:修改成功,并显示成功提示
实际结果:修改成功,并显示成功提示,与预期结果一致
场景3:修改密码,输入错误的原密码,新密码确认密码一致
预期结果:修改失败,并显示原密码不正确
实际结果:修改失败,并正确显示原密码不正确,与预期结果一致
场景4:修改密码,输入正确的原密码,新密码确认密码不一致
预期结果:修改失败,并提示两次输入的密码不相同
实际结果:修改失败,并正确提示两次输入的密码不相同,与预期结果一致
3.1.4 站内信功能测试
场景1:发送站内信,成功后显示成功提示
预期结果:发送成功,显示成功提示
实际结果:发送成功,并正确显示成功提示,与预期结果一致
场景2:查看站内信
预期结果:可以看到3种状态,未读,已读,已回复
实际结果:显示成功共三种状态,与预期结果一致
3.1.5 板块功能测试
场景1:点击java板块
预期结果:可以跳转到java板块,并显示java板块的帖子及数量,导航栏有蓝色标识
实际结果:成功跳转到java板块,显示java板块的帖子及数量,导航栏有蓝色,标识与预期结果一致
3.1.6 帖子功能测试
场景1:发布帖子
预期结果:点击发布帖子,跳转到发帖页面,正确发布帖子,发帖成功,跳转到首页,最上方显示新增的帖子,且对应板块下帖子数量更新, 并显示发帖成功
实际结果:成功跳转到java板块,显示java板块的帖子及数量,导航栏有蓝色,标识与预期结果一致
场景2: 编辑帖子,点击编辑按钮,正确跳转到编辑帖子页面,点击提交按钮
预期结果:编辑成功,提示修改成功
实际结果:点击编辑按钮,正确跳转到编辑帖子页面,点击提交按钮,编辑成功,显示修改成功,与预期结果一致
场景3:点赞帖子,点击点赞按钮
预期结果:点赞成功,提示点赞成功,帖子点赞数对应增加
实际结果:点击编辑按钮,正确跳转到编辑帖子页面,点击提交按钮,编辑成功,显示修改成功,与预期结果一致
场景4:评论帖子输入回复内容,点击回复,
预期结果:回复成功,显示回复内容,并有提示回复成功
实际结果:回复成功,显示回复内容,并有提示回复成功,与预期结果一致
场景5:删除帖子,点击删除按钮,出现确认弹窗,点击删除
预期结果:删除成功,提示删除成功,帖子数对应减少
实际结果:删除成功,提示删除成功,帖子数对应减少,与预期结果一致
3.2 UI自动化测试
3.2.1 Utils 类
创建driver对象,测试过程中屏幕截图的通用工具类:
package common;
import io.github.bonigarcia.wdm.WebDriverManager;
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 java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.Duration;
public class Utils {
public static WebDriver driver;
//创建driver对象
public static WebDriver createDriver() {
if (driver == null) {
//驱动管理打开chrome浏览器
WebDriverManager.chromedriver().setup();
//对chrome浏览器进行设置
ChromeOptions options = new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
driver = new ChromeDriver(options);
//全局隐式等待
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(2));
}
return driver;
}
public Utils(String url){
driver=createDriver();
driver.get(url);
}
//屏幕截图
public void getScreenShot(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/image/"+dirTime+"/"+str+"-"+fileTime+".png";
File srcFile=((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(srcFile,new File(filename));
}
}
3.2.2 LoginPage 类
测试登录功能:
package tests;
import common.Utils;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import java.io.File;
import java.io.IOException;
import java.time.Duration;
public class LoginPage extends Utils {
public static String url = "http://127.0.0.1:58080/sign-in.html";
public LoginPage() {
super(url);
}
public void LoginPageRight() throws IOException {
//通过登录界面图标检查页面加载是否成功
driver.findElement(By.cssSelector("body > div > div > div > div.col-lg.d-none.d-lg-block > img"));
//登录输入框
driver.findElement(By.cssSelector("body > div > div > div > div:nth-child(1) > div > div.card.card-md > div"));
getScreenShot(getClass().getName());
}
/**
* 测试登录成功功能
*/
public void LoginPageSuc() throws IOException {
//通过clear保证输入框没有文本
driver.findElement(By.cssSelector("#username")).clear();
driver.findElement(By.cssSelector("#password")).clear();
driver.findElement(By.cssSelector("#username")).sendKeys("admin");
driver.findElement(By.cssSelector("#password")).sendKeys("123456");
driver.findElement(By.cssSelector("#submit")).click();
//检查登陆之后结果是否成功--发布帖子按钮
driver.findElement(By.cssSelector("#bit-forum-content > div.page-header.d-print-none > div > div > div.col-auto.ms-auto.d-print-none > div > a.btn.btn-primary.d-none.d-sm-inline-block.article_post"));
getScreenShot(getClass().getName());
driver.navigate().back();
driver.quit();
}
/**
* 测试登录失败
*/
public void LoginFail() throws IOException {
//通过clear保证输入框没有文本
driver.findElement(By.cssSelector("#username")).clear();
driver.findElement(By.cssSelector("#password")).clear();
driver.findElement(By.cssSelector("#username")).sendKeys("admi");
driver.findElement(By.cssSelector("#password")).sendKeys("123456");
driver.findElement(By.cssSelector("#submit")).click();
//HTML弹窗错误警告
driver.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-right > div"));
getScreenShot(getClass().getName());
driver.quit();
}
}
3.2.3 RegistPage 类
测试注册用户功能:
package tests;
import common.Utils;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import java.io.IOException;
public class RegistPage extends Utils {
public static String url = "http://127.0.0.1:58080/sign-up.html";
public RegistPage() {
super(url);
}
public void RegistPageRight() throws IOException {
//通过注册界面图标检查页面加载是否成功
driver.findElement(By.cssSelector("body > div > div > div.text-center.mb-4 > img"));
//注册输入框
driver.findElement(By.cssSelector("#signUpForm > div"));
getScreenShot(getClass().getName());
}
/**
* 测试注册成功功能
*/
public void RegistSuc() throws IOException {
//通过clear保证输入框没有文本
driver.findElement(By.cssSelector("#username")).clear();
driver.findElement(By.cssSelector("#nickname")).clear();
driver.findElement(By.cssSelector("#password")).clear();
driver.findElement(By.cssSelector("#passwordRepeat")).clear();
WebElement checkbox = driver.findElement(By.cssSelector("#policy"));
if (checkbox.isSelected()) {
checkbox.click();
}
driver.findElement(By.cssSelector("#username")).sendKeys("wangwu");
driver.findElement(By.cssSelector("#nickname")).sendKeys("王五");
driver.findElement(By.cssSelector("#password")).sendKeys("123456");
driver.findElement(By.cssSelector("#passwordRepeat")).sendKeys("123456");
driver.findElement(By.cssSelector("#policy")).click();
driver.findElement(By.cssSelector("#submit")).click();
//检查注册之后跳转到登录结果是否成功--登录框
driver.findElement(By.cssSelector("body > div > div > div > div:nth-child(1) > div > div.card.card-md > div"));
getScreenShot(getClass().getName());
driver.navigate().back();
}
/**
* 测试注册失败
*/
public void RegistFail() throws IOException {
driver.get("http://127.0.0.1:58800/sign-up.html");
//通过clear保证输入框没有文本
driver.findElement(By.cssSelector("#username")).clear();
driver.findElement(By.cssSelector("#nickname")).clear();
driver.findElement(By.cssSelector("#password")).clear();
driver.findElement(By.cssSelector("#passwordRepeat")).clear();
WebElement checkbox = driver.findElement(By.cssSelector("#policy"));
if (checkbox.isSelected()) {
checkbox.click();
}
driver.findElement(By.cssSelector("#username")).sendKeys("zhangsan");
driver.findElement(By.cssSelector("#nickname")).sendKeys("张三");
driver.findElement(By.cssSelector("#password")).sendKeys("123456");
driver.findElement(By.cssSelector("#passwordRepeat")).sendKeys("111111");
driver.findElement(By.cssSelector("#policy")).click();
driver.findElement(By.cssSelector("#submit")).click();
//注册失败--页面不会跳转,定位注册登录框
driver.findElement(By.cssSelector("#signUpForm > div"));
getScreenShot(getClass().getName());
driver.quit();
}
}
3.2.4 PageByNoLogin 类
登录状态下访问主页:
package tests;
import common.Utils;
import org.openqa.selenium.By;
import java.io.IOException;
public class PageByNoLogin extends Utils {
public static String url = "http://127.0.0.1:58080/index.html";
public PageByNoLogin() {
super("");
}
//未登录状态下,访问版块界面,不能进入:"网页无法正常运作"
public void BoardNoLogin() throws IOException {
driver.get(url);
driver.findElement(By.cssSelector("html"));
getScreenShot(getClass().getName());
driver.quit();
}
}
3.2.5 BoardPage 类
登录状态下,点击首页的帖子,进入帖子详情界面,测试点赞、编辑、回复、删除的功能:
package tests;
import common.Utils;
import org.openqa.selenium.*;
import org.openqa.selenium.interactions.Actions;
import java.io.IOException;
public class BoardPage extends Utils {
public static String url = "http://127.0.0.1:58080/index.html";
public BoardPage() {
super(url);
}
//登录状态下,访问版块界面
public void BoardByLogin() throws IOException, InterruptedException {
driver.findElement(By.cssSelector("#article_list_board_title"));
//用户可以点击界面切换按钮
driver.findElement(
By.cssSelector
("body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div.d-none.d-md-flex > a.nav-link.px-0.hide-theme-dark > svg")).click();
//版块界面,自己的发的帖子,可以点赞,编辑,删除,回复(此处登录账号为liuliu)
driver.findElement(By.cssSelector("#artical-items-body > div:nth-child(1) > div > div.col > div.text-truncate > a > strong")).click();
//点赞
driver.findElement(By.cssSelector("#details_btn_like_count")).click();
driver.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-right > div > span.close-jq-toast-single")).click();
//回复
WebElement ele = driver.findElement(By.cssSelector("#article_details_reply > div.CodeMirror.cm-s-default.CodeMirror-wrap.CodeMirror-empty > div.CodeMirror-scroll > div.CodeMirror-sizer > div > div > div > div.CodeMirror-code > div > pre"));
Actions actions = new Actions(driver);
actions.doubleClick(ele);
actions.moveToElement(ele).sendKeys("已回复");
//html弹窗显示成功回复
driver.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-right > div > span.close-jq-toast-single")).click();
//编辑
driver.findElement(By.cssSelector("#details_artile_edit")).click();
//点击编辑跳转到编辑界面:定位元素“编辑”,修改提交之后(有默认内容,不必修改,直接提交),跳转到首页
driver.findElement(By.cssSelector("#bit-forum-content > div.page-header.d-print-none > div > div > div > h2"));
// 使用 JavaScript 滚动到页面底部
((JavascriptExecutor) driver).executeScript("window.scrollTo(0, document.body.scrollHeight);");
Thread.sleep(5000);
WebElement element = driver.findElement(By.cssSelector("#edit_article_submit"));
element.click();
driver.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-right > div > span.close-jq-toast-single")).click();
Thread.sleep(2000);
//删除按钮
driver.findElement(By.cssSelector("#artical-items-body > div:nth-child(1) > div > div.col > div.text-truncate > a > strong")).click();
driver.findElement
(By.cssSelector
("#bit-forum-content > div.page-body > div > div > div:nth-child(1) > div.col-9.card.card-lg > div.card-footer.bg-transparent.mt-auto.justify-content-end > div > div:nth-child(3) > div > a")).click();
//处理html弹窗
driver.findElement(By.cssSelector("#details_delete_modal > div > div > div.modal-body.text-center.py-4"));
//点击取消按钮
driver.findElement(By.cssSelector("#details_delete_modal > div > div > div.modal-footer > div > div > div:nth-child(1) > a")).click();
getScreenShot(getClass().getName());
driver.quit();
}
}
3.2.6 ArticleEditPage 类
在登陆状态下,测试发贴流程:点击首页“发布帖子”按钮,进入发帖界面,输入标题和内容,点击提交按钮成功发布:
package tests;
import common.Utils;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import java.io.IOException;
public class ArticleEditPage extends Utils {
public static String url = "http://127.0.0.1:58080/index.html";
public ArticleEditPage() {
super(url);
}
//登录状态下,访问发布帖子界面
public void ArticleEditByLogin() throws IOException {
driver.findElement(By.cssSelector("body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > h1 > a > img"));
WebElement ele = driver.findElement(By.cssSelector("#bit-forum-content > div.page-header.d-print-none > div > div > div.col-auto.ms-auto.d-print-none > div > a.btn.btn-primary.d-none.d-sm-inline-block.article_post"));
ele.click();
driver.findElement(By.cssSelector("#article_post_title")).sendKeys("自动化测试标题");
WebElement ele2 = driver.findElement(By.cssSelector("#edit-article > div.CodeMirror.cm-s-default.CodeMirror-wrap.CodeMirror-empty > div.CodeMirror-scroll > div.CodeMirror-sizer > div > div > div > div.CodeMirror-code > div > pre"));
Actions actions = new Actions(driver);
actions.doubleClick(ele2);
actions.moveToElement(ele2).sendKeys("自动化测试内容");
driver.findElement(By.cssSelector("#article_post_submit")).click();
driver.findElement(By.cssSelector("body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > h1 > a > img"));
getScreenShot(getClass().getName());
driver.quit();
}
}
3.2.7 MessagePage 类
测试修改个人信息:昵称、邮箱地址、手机号、个人简介、修改密码:
package tests;
import common.Utils;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import java.io.IOException;
public class MessagePage extends Utils {
public static String url = "http://127.0.0.1:58080/index.html";
public MessagePage() {
super(url);
}
public void MessageByLogin() throws IOException{
// 使用 JavaScript 将页面缩放比例设置为 50%
((JavascriptExecutor) driver).executeScript("document.body.style.zoom = '0.5';");
driver.findElement(By.cssSelector("#article_list_board_title"));
//用户可以点击头像,点击个人中心
driver.findElement(By.cssSelector("#index_nav_avatar")).click();
driver.findElement(By.cssSelector("#index_user_settings")).click();
//清除之前存在的内容
driver.findElement(By.cssSelector("#setting_input_nickname")).clear();
driver.findElement(By.cssSelector("#setting_input_email")).clear();
driver.findElement(By.cssSelector("#setting_input_phoneNum")).clear();
driver.findElement(By.cssSelector("#settings_input_oldPassword")).clear();
driver.findElement(By.cssSelector("#settings_input_newPassword")).clear();
driver.findElement(By.cssSelector("#settings_input_passwordRepeat")).clear();
driver.findElement(By.cssSelector("#settings_textarea_remark")).clear();
//修改昵称
driver.findElement(By.cssSelector("#setting_input_nickname")).sendKeys("AAAA");
driver.findElement(By.cssSelector("#setting_submit_nickname")).click();
driver.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-right > div > span.close-jq-toast-single")).click();
//修改邮箱地址
driver.findElement(By.cssSelector("#setting_input_email")).sendKeys("12345678@qq.com");
driver.findElement(By.cssSelector("#setting_submit_email")).click();
driver.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-right > div > span.close-jq-toast-single")).click();
//修改电话号码
driver.findElement(By.cssSelector("#setting_input_phoneNum")).sendKeys("13888888888");
driver.findElement(By.cssSelector("#setting_submit_phoneNum")).click();
driver.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-right > div > span.close-jq-toast-single")).click();
//修改个人简介
((JavascriptExecutor) driver).executeScript("window.scrollTo(0, document.body.scrollHeight);");
driver.findElement(By.cssSelector("#settings_textarea_remark")).sendKeys("修改");
driver.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-right > div > span.close-jq-toast-single")).click();
//修改密码
driver.findElement(By.cssSelector("#settings_input_oldPassword")).sendKeys("111111");
driver.findElement(By.cssSelector("#settings_input_newPassword")).sendKeys("123456");
driver.findElement(By.cssSelector("#settings_input_passwordRepeat")).sendKeys("123456");
driver.findElement(By.cssSelector("#settings_submit_password")).click();
driver.findElement(By.cssSelector("body > div > div > div > div.col-lg.d-none.d-lg-block > img"));
getScreenShot(getClass().getName());
driver.quit();
}
}
3.2.8 RunTests 类
测试运行类:
package tests;
import tests.*;
import java.io.IOException;
public class RunTests {
public static void main(String[] args) throws IOException, InterruptedException {
LoginPage login = new LoginPage();
login.LoginPageRight();
login.LoginPageSuc();
login.LoginFail();
RegistPage regist = new RegistPage();
regist.RegistPageRight();
regist.RegistSuc();
regist.RegistFail();
PageByNoLogin page = new PageByNoLogin();
page.BoardNoLogin();
BoardPage board = new BoardPage();
board.BoardByLogin();
ArticleEditPage edit = new ArticleEditPage();
edit.ArticleEditByLogin();
MessagePage message = new MessagePage();
message.MessageByLogin();
}
}