一、项目介绍
基于Spring前后端分离的博客论坛系统,实现了注册、登录、显示帖子、编辑帖子、删除帖子、回复帖子、点赞帖子,修改个人信息等功能,并将其部署到云服务器上。
技术要点:
- 使用统一返回格式+全局错误信息定义前后端交互时的返回结果;
- 使用@ControllerAdvice+@ExceptionHandler实现全局异常处理;
- 使用拦截器实现用户登录校验等页面过滤功能;
- 使用MD5和UUID等加密算法对用户密码进行加密,提高系统的安全性和数据保护能力;
- 使用MybatisGeneratorConfig实现自动生成常用的增删查改方法;
访问地址: 论坛 - 用户登录
二、测试计划
1.功能测试
1.1 测试环境
操作系统:Windows 10家庭版
项目运行环境:IIntelliJ IDEA Community Edition 2023.2.2、 JDK17、MySQL5.7
浏览器:Chorme、Edge、360极速浏览器
自动化脚本环境:IIntelliJ IDEA Community Edition 2023.2.2
访问链接:论坛 - 用户登录
测试技术: 主要手工进行单元测试和自动化测试, 使用性能测试工具LoadRunner进行登录界面测试
测试人员: 本人
1.2 测试用例编写
1.2.1 功能测试:
1.2.2 非功能测试:
1.3.部分功能测试
1.3.1 对注册页面进行测试
- 场景1:
输入用户名存在,密码与确认密码一致,点击注册
预期结果:提示用户已经存在
实际结果:提示用户已经存在,与预期结果一致。
- 场景2:
输入用户名不存在,密码与却密码一致,点击注册
预期结果:注册成功,跳转回登录界面
实际结果:注册成功,跳转回登录界面,与预期结果一致。
1.3.2 对登录界面进行测试
- 场景1:
输入用户名存在,密码与确认密码一致,点击登录
预期结果:登录成功,跳转到首页博客列表页面
实际结果:与预期结果一致。
- 场景2:
输入用户名存在,密码与确认密码不一致,点击登录
预期结果:登录失败,给出错误提示
实际结果:登录失败,给出错误提示。
1.3.3 对首页进行测试
- 场景1:
登录状态下,点击首页
预期结果:导航栏显示所有的版块名,下方显示所有帖子列表,右上方显示登录用户信息。
实际结果:与预期结果一致。
- 场景2:
登录状态下,点击前端技术, 预期结果:下方显示C++名称,该版块下的帖子数量,版块下的所有帖子列表,右上方显示登录用户信息。
实际结果:与预期结果一致。
- 场景3:
登录状态下,在搜索框输入关键字“数据库”搜索
预期结果:下方显示帖子正文中所有存在“数据库”这三个字的帖子;
实际结果:刷新回到首页界面,与预期不符。不支持搜索功能。
- 场景4:
登录状态下,点击“月亮”按钮
预期结果:进入夜间模式的切换
实际结果:进入夜间模式的切换,与预期相符。
- 场景5
登录状态下,点击“发布帖子”按钮
预期结果:进入博客编辑页面,版块名默认选择Java
实际结果:与预期相符。
1.3.4 对编辑帖子页面进行测试
- 场景1:
未登录状态下,进入编辑页面
预期结果:跳转回登录界面
实际结果:跳转回登录界面,与预期结果一致。
- 场景2:
登录状态下,不输入帖子标题,输入帖子内容,点击发布
预期结果:给出提示:请输入帖子标题
实际结果:与预期相符。
- 场景3:
登录状态下,输入帖子标题,输入帖子内容,点击发布
预期结果:编辑成功,跳转回首页,最上方显示刚发布的帖子信息
实际结果:与预期相符。
1.3.5 对帖子详情页面进行测试
- 场景1:
登录状态下,点击首页下的一条帖子内容“测试博客内容”
预期结果:跳转到该帖子详情页面,当前帖子是作者发布的,出现编辑和删除按钮
实际结果:与预期相符。
- 场景2:
登录状态下,点击首页下的一条帖子内容“哈哈哈哈哈哈哈哈”(帖子作者“小白”,当前登录作者“1234”)
预期结果:跳转到该帖子详情页面,最上方显示帖子信息,左侧显示帖子作者信息,下方显示该帖子的内容,下方只显示点赞按钮。
实际结果:与预期相符。
- 场景3:
登录状态下,下方点赞按钮
预期结果:上方显示的点赞数加1
实际结果:与预期相符。
- 场景4:
登录状态下,点击首页下的一条帖子内容“123”,观察访问数变化
预期结果:跳转到该帖子详情页面,最上方显示帖子信息中的访问数+1
实际结果:与预期相符。
- 场景5:
登录状态下,点击发私信按钮,不输入文本内容,点击“发送”
预期结果:给出警告提示:请输入要发送的内容
实际结果:与预期相符。
- 场景6
登录状态下,点击发私信按钮,输入文本内容,点击“发送”
预期结果:给出成功提示,发送成功
实际结果:与预期相符。
- 场景7
登录状态下,在下方的回复框中不输入文本内容,点击“回复”
预期结果:给出警告提示,请输入回复内容
实际结果:与预期相符。
- 场景8
登录状态下,在下方的回复框中输入文本内容,点击“回复”
预期结果:给出成功提示,同时下方显示回复内容。
实际结果:与预期相符。
1.3.6 对个人中心页面进行测试
- 场景1
未登录状态下,点击首页下的任意一条帖子内容
预期结果:跳转回登录界面
实际结果:跳转回登录界面,与预期结果一致。
- 场景2 登录状态下,点击“我的帖子”
预期结果:下方显示该登录用户的所有帖子信息
实际结果:与预期相符。
- 场景3
登录状态下,点击“个人中心”
预期结果:下方显示该登录用户的所有信息
实际结果:与预期相符。
- 场景4
登录状态下,“修改昵称”
预期结果:输入修改后的昵称,并刷新成功
实际结果:与预期一致。
- 场景5
登录状态下,“修改密码”:原密码错误,新密码和确认密码一致,点击修改密码
预期结果:给出警告提示:原密码有误。
实际结果:输出后端具体代码信息,与预期不一致。
.................
这里只给出部分测试,其它功能就不一一测试了。
2.自动化测试
2.1 注册页面测试
2.1.1验证注册成功的情况
- 场景1:
注册用户名在数据库不存在,昵称,两次密码一致,注册成功,跳转回登录界面。
/**
* 场景1:不存在的用户名,昵称,两次密码一致
*/
public class RegisterTest {
@Order(1)
@ParameterizedTest
@CsvSource(value = {"apple1,apple,123456,123456"})
void testRegister(String username,String nickName,String password,String password1) throws InterruptedException, IOException {
WebDriver webDriver = new ChromeDriver();
webDriver.get("http://8.130.40.249:8080//sign-in.html");
//配置全局的变量-隐式等待
//webDriver.manage().timeouts().implicitlyWait(1, TimeUnit.DAYS);
Thread.sleep(7000);
//点击注册按钮
webDriver.findElement(By.cssSelector("body > div > div > div > div:nth-child(1) > div > div.text-center.text-muted.mt-3 > a")).click();
//输入用户名
webDriver.findElement(By.cssSelector("#username")).sendKeys(username);
//输入昵称
webDriver.findElement(By.cssSelector("#nickname")).sendKeys(nickName);
//输入密码
webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
//再次校验密码
webDriver.findElement(By.cssSelector("#passwordRepeat")).sendKeys(password1);
//点击复选框
webDriver.findElement(By.cssSelector("#policy")).click();
// 点击提交
webDriver.findElement(By.cssSelector("#submit")).click();
Thread.sleep(7000);
//判断注册成功后,是否跳转到登录界面
String actualUrl = webDriver.getCurrentUrl();
String expectUrl = "http://8.130.40.249:8080/sign-in.html";
Assertions.assertEquals(expectUrl,actualUrl);
System.out.println("注册成功");
//进行截图
File file = ((TakesScreenshot)webDriver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(file,new File("D:\registerTest.png"));
webDriver.navigate().back();
}
}
2.1.2 验证注册失败的情况
- 场景1:
注册用户名在数据库存在,昵称,两次密码一致,注册失败,获取警告框信息。
代码同上。
测试结果
2.2 登录页面测试
2.2.1 登录成功测试
测试用户名正确,密码正确,登录成功
/**
* 用户名 密码都正确
* 用户名: apple1
* 密码: 123456
*/
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class login {
@ParameterizedTest
@CsvSource({"apple1,123456,123456"})
void loginTest(String userName,String password,String password1) throws InterruptedException, IOException {
WebDriver webDriver = new ChromeDriver();
webDriver.get("http://8.130.40.249:8080//sign-in.html");
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
// 输入用户名
webDriver.findElement(By.cssSelector("#username")).sendKeys(userName);
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
// 输入密码
webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
// 点击提交
webDriver.findElement(By.cssSelector("#submit")).click();
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.MINUTES);
Thread.sleep(1000); // 显示等待,等待弹窗出现
// 上述步骤只是说明输入了账号和密码,但还不知道点击提交后是否会跳转到博客列表页
String expect = "http://8.130.40.249:8080/index.html";
String actual = webDriver.getCurrentUrl();//
// // 进行截图,看当前是否跳转到了登录界面
webDriver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
Assertions.assertEquals(expect, actual); // 查看当前的url是否在博客详情页面
File srcFile = ((TakesScreenshot)webDriver).getScreenshotAs(OutputType.FILE);
String fileName = "loginTest.png";
FileUtils.copyFile(srcFile, new File(fileName));
Thread.sleep(1000); // 显示等待,等待弹窗出现
//因为我们要测试多个账号,所有在一个账号检测完了后,还需要回退到登录界面
webDriver.navigate().back();
}
}
2.2.2 登陆失败测试
场景1:测试用户名正确,密码错误,登录失败
/**
* 用户名输入正确 密码不输入
* 用户名: apple1
* 密码: 123456
*/
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class login {
@ParameterizedTest
@CsvSource({"apple1,''"}) //拿单引号来表示不输入
void loginTest(String userName,String password) throws InterruptedException, IOException {
WebDriver webDriver = new ChromeDriver();
webDriver.get("http://8.130.40.249:8080//sign-in.html");
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
// 输入用户名
webDriver.findElement(By.cssSelector("#username")).sendKeys(userName);
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
// 输入密码
webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
// 点击提交
webDriver.findElement(By.cssSelector("#submit")).click();
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.MINUTES);
}
}
2.3 显示帖子列表页面测试
- 场景1:
未登录状态,进入帖子列表首页,返回到登录界面
public class articleList {
@Test
void testArticleList() throws InterruptedException {
WebDriver webDriver = new ChromeDriver();
webDriver.get("http://8.130.40.249:8080//index.html");
String expectURL = "http://8.130.40.249:8080/sign-in.html";
webDriver.manage().timeouts().implicitlyWait(1, TimeUnit.DAYS);
String autural = webDriver.getCurrentUrl();
Assertions.assertEquals(expectURL,autural);
}
}
未登录,跳转回登录界面
- 场景2:
登录状态下,从登录界面正常进入帖子列表首页,查看首页元素是否存在,查看编辑帖子阶段是否有 "发新贴" 元素存在
/**
*登录状态下,进入博客列表页,是否正确显示帖子相应的控件信息
* @param username 用户名
* @param password 密码
* @throws InterruptedException
*/
@Order(2)
@ParameterizedTest
@CsvSource({"apple1,123456"})
void testAticlelist(String username,String password) throws InterruptedException {
WebDriver webDriver = new ChromeDriver();
webDriver.get("http://8.130.40.249:8080/sign-in.html");
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
// 输入用户名
webDriver.findElement(By.cssSelector("#username")).sendKeys(username);
// 输入密码
webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
// 点击提交
webDriver.findElement(By.cssSelector("#submit")).click();
Thread.sleep(3000);
//判断列表首页 二字是否存在是否存在
String expectChar = "首页";
String auturalChar = webDriver.findElement(By.cssSelector("#nav_board_index > a > span.nav-link-title")).getText();
Assertions.assertEquals(expectChar,auturalChar);
//查看是否有发布帖子按钮,点击后跳转到的页面是否 有 发新帖二字
webDriver.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")).click();
Thread.sleep(3000);
String expect = "发新贴";
String autural = webDriver.findElement(By.cssSelector(".page-title")).getText();
Assertions.assertEquals(expect,autural);
}
2.4 发布帖子测试
- 场景1:
登录后,输入帖子标题,不输入帖子内容,点击发布按钮,给出提示信息。
@Order(3)
@ParameterizedTest
@CsvSource({"apple1,123456"})
void testsEenArticle(String username,String password) throws InterruptedException, IOException {
WebDriver webDriver = new ChromeDriver();
webDriver.get("http://8.130.40.249:8080/sign-in.html");
webDriver.manage().window().maximize();
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
webDriver.findElement(By.cssSelector("#username")).sendKeys(username);
webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
webDriver.findElement(By.cssSelector("#submit")).click();
Thread.sleep(3000);
webDriver.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")).click();
webDriver.findElement(By.cssSelector("#article_post_title")).sendKeys("测试掘金文章");
//内容不输入
Thread.sleep(7000);
//将滚动条放到最下面
JavascriptExecutor js = (JavascriptExecutor) webDriver;
js.executeScript("document.documentElement.scrollTop= 2000");//x 表示文档顶部距离视口顶部的距离
//点击提交按钮
webDriver.findElement(By.cssSelector("#article_post_submit")).click();
}
}
2.5 帖子详情页测试
2.5.1 未登录状态
- 场景1:
未登录状态下,进入帖子详情页,直接跳转回登录界面。
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class articleDetail {
/**
* 未登录状态下,进入博客详情页,是否跳转回登录页面
* @throws InterruptedException
* @throws IOException
*/
@Order(1)
@Test
void BlogDetail1() throws InterruptedException, IOException {
WebDriver webDriver = new ChromeDriver();
//1-不登录,直接打开博客详情页
webDriver.get("http://8.130.40.249:8080/index.html");
//获取当前的url地址
String expect = "http://8.130.40.249:8080/sign-in.html";
String actual = webDriver.getCurrentUrl();
//判断是否跳转到登录界面
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
Assertions.assertEquals(expect, actual);
//截图
File srcFile = ((TakesScreenshot)webDriver).getScreenshotAs(OutputType.FILE);
String fileName = "BlogListFailed.png";
FileUtils.copyFile(srcFile, new File(fileName));
}
}
2.5.2 登录状态
场景1:
登录状态,点击其它用户的帖子,判断帖子详情是否正确,点赞功能是否正常
@Order(2)
@ParameterizedTest
@CsvSource({"apple1,123456"})
void BlogDetail2(String userName,String password){
WebDriver webDriver = new ChromeDriver();
webDriver.get("http://8.130.40.249:8080//sign-in.html");
webDriver.manage().window().maximize();
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
// 输入用户名
webDriver.findElement(By.cssSelector("#username")).sendKeys(userName);
// 输入密码
webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
// 点击提交
webDriver.findElement(By.cssSelector("#submit")).click();
//点击帖子标题为"测试博客内容",作者为1234 的帖子
//当前登录用户为 apple1,帖子作者与登录作者不一致,只显示点赞按钮
webDriver.findElement(By.cssSelector("#artical-items-body > div:nth-child(2) > div > div.col > div.text-truncate > a > strong")).click();
//帖子详情页是否有帖子标题
System.out.println(webDriver.findElement(By.cssSelector("#details_article_content_title")).getText());
//帖子内容
System.out.println(webDriver.findElement(By.cssSelector("#details_article_content > p")).getText());
//帖子作者
System.out.println(webDriver.findElement(By.cssSelector("#article_details_author_name")).getText());
//进行点赞
webDriver.findElement(By.cssSelector("#details_btn_like_count")).click();
}
- 场景2
登录状态下,点击自己的帖子,出现 编辑、点赞、删除等元素
@Order(3)
@ParameterizedTest
@CsvSource({"apple1,123456"})
void BlogDetails3(String userName,String password){
WebDriver webDriver = new ChromeDriver();
webDriver.get("http://8.130.40.249:8080//sign-in.html");
webDriver.manage().window().maximize();
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
// 输入用户名
webDriver.findElement(By.cssSelector("#username")).sendKeys(userName);
// 输入密码
webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
// 点击提交
webDriver.findElement(By.cssSelector("#submit")).click();
//当前帖子标题为:apple 作者是 apple
webDriver.findElement(By.cssSelector("#artical-items-body > div:nth-child(1) > div > div.col > div.text-truncate > a > strong")).click();
//查看是否有编辑按钮
webDriver.findElement(By.cssSelector("#details_artile_edit > span"));
//查看是否有 删除按钮
webDriver.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"));
}
2.6 删除帖子测试
登录后,进入帖子详情页,点击删除按钮,删除帖子成功,成功跳转回帖子列表页面
@Order(4)
@ParameterizedTest
@CsvSource({"apple1,123456"})
void testArticleDelete(String userName,String password){
//1 登录
WebDriver webDriver = new ChromeDriver();
webDriver.get("http://8.130.40.249:8080//sign-in.html");
webDriver.manage().window().maximize();
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
webDriver.findElement(By.cssSelector("#username")).sendKeys(userName);
webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
webDriver.findElement(By.cssSelector("#submit")).click();
//当前帖子标题为:apple 作者是 apple
webDriver.findElement(By.cssSelector("#artical-items-body > div:nth-child(1) > div > div.col > div.text-truncate > a > strong")).click();
//进行删除
webDriver.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();
webDriver.findElement(By.cssSelector("#details_artile_delete")).click();
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
//判断是否跳转回博客列表页面
String expectUrl="http://8.130.40.249:8080/index.html";
String auturalUrl = webDriver.getCurrentUrl();
Assertions.assertEquals(expectUrl,auturalUrl);
}
2.7 个人中心显示
2.7.1未登录状态
未登录状态下,进入博客列表页,点击我的帖子(都走不到这一步),跳转回登录页面。
2.7.2 登录状态
- 场景1:
登录状态下,进入博客列表页,点击我的帖子,跳转到个人中心页面,显示用户昵称等信息。
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class PersonCenter {
@Order(1)
@ParameterizedTest
@CsvSource({"apple1,123456"})
void loginTest(String userName, String password) throws InterruptedException, IOException {
WebDriver webDriver = new ChromeDriver();
webDriver.get("http://8.130.40.249:8080/sign-in.html");
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
//登录
webDriver.findElement(By.cssSelector("#username")).sendKeys(userName);
webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
webDriver.findElement(By.cssSelector("#submit")).click();
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.MINUTES);
//点击我的帖子
webDriver.findElement(By.cssSelector("#index_nav_name_sub")).click();
Thread.sleep(1000);
webDriver.findElement(By.cssSelector("#index_user_profile")).click();
//是否有用户昵称
webDriver.findElement(By.cssSelector("#profile_nickname"));
//截图
File srcFile = ((TakesScreenshot)webDriver).getScreenshotAs(OutputType.FILE);
String fileName = "CenterInfoSuccess.png";
FileUtils.copyFile(srcFile, new File(fileName));
}
}
2.8 显示个人信息并修改
2.8.1未登录状态
未登录状态下,进入帖子列表页,点击用户头像下的个人中心(都走不到这一步),跳转回登录页面。
2.8.2登录状态
场景1: 登录显示个人信息测试
@Order(2)
@ParameterizedTest
@CsvSource(value = "apple1, 123456")
void BlogList2(String username, String password) throws InterruptedException, IOException {
WebDriver webDriver = new ChromeDriver();
//1-登录
// 打开登录页面
webDriver.get("http://8.130.40.249:8080/sign-in.html");
webDriver.manage().window().maximize();
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
webDriver.findElement(By.cssSelector("#username")).sendKeys(username);
webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
// 点击提交
webDriver.findElement(By.cssSelector("#submit")).click();
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.MINUTES);
//2-点击我的帖子
webDriver.findElement(By.cssSelector("#index_nav_avatar")).click();
Thread.sleep(1000);
webDriver.findElement(By.cssSelector("#index_user_settings")).click();
Thread.sleep(1000);
//是否有用户昵称
webDriver.findElement(By.cssSelector("#settings_nickname"));
//是否有“昵称”这两个字
webDriver.findElement(By.cssSelector(" #bit-forum-content > div.page-body > div > div > div > div.col.d-flex.flex-column > div > h3:nth-child(4)"));
//是否有“邮箱地址”这几个字
webDriver.findElement(By.cssSelector(" #bit-forum-content > div.page-body > div > div > div > div.col.d-flex.flex-column > div > h3:nth-child(7)"));
//是否有“电话号码”这几个字
webDriver.findElement(By.cssSelector(" #bit-forum-content > div.page-body > div > div > div > div.col.d-flex.flex-column > div > h3:nth-child(10)"));
//是否有“修改密码”这几个字
webDriver.findElement(By.cssSelector(" #bit-forum-content > div.page-body > div > div > div > div.col.d-flex.flex-column > div > h3:nth-child(13)"));
//是否有“提交修改”按钮#settings_input_passwordRepeat
webDriver.findElement(By.cssSelector("#settings_submit_password"));
Thread.sleep(1000);
}
测试结果:
场景2,登录后修改昵称测试
@Order(3)
@ParameterizedTest
@CsvSource(value = "apple1, 123456")
void BlogList2(String username, String password) throws InterruptedException, IOException {
WebDriver webDriver = new ChromeDriver();
//1-登录
// 打开登录页面
webDriver.get("http://8.130.40.249:8080/sign-in.html");
webDriver.manage().window().maximize();
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
webDriver.findElement(By.cssSelector("#username")).sendKeys(username);
webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
// 点击提交
webDriver.findElement(By.cssSelector("#submit")).click();
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.MINUTES);
//2-点击我的帖子
webDriver.findElement(By.cssSelector("#index_nav_avatar")).click();
Thread.sleep(1000);
webDriver.findElement(By.cssSelector("#index_user_settings")).click();
Thread.sleep(1000);
//是否有用户昵称
webDriver.findElement(By.cssSelector("#settings_nickname"));
//是否有“昵称”这两个字
webDriver.findElement(By.cssSelector(" #bit-forum-content > div.page-body > div > div > div > div.col.d-flex.flex-column > div > h3:nth-child(4)"));
//是否有“邮箱地址”这几个字
webDriver.findElement(By.cssSelector(" #bit-forum-content > div.page-body > div > div > div > div.col.d-flex.flex-column > div > h3:nth-child(7)"));
//是否有“电话号码”这几个字
webDriver.findElement(By.cssSelector(" #bit-forum-content > div.page-body > div > div > div > div.col.d-flex.flex-column > div > h3:nth-child(10)"));
//是否有“修改密码”这几个字
webDriver.findElement(By.cssSelector(" #bit-forum-content > div.page-body > div > div > div > div.col.d-flex.flex-column > div > h3:nth-child(13)"));
//是否有“提交修改”按钮#settings_input_passwordRepeat
webDriver.findElement(By.cssSelector("#settings_submit_password"));
Thread.sleep(1000);
//3-修改昵称
//清除昵称的文本内容
webDriver.findElement(By.cssSelector("#setting_input_nickname")).clear();
//输入要修改的内容
webDriver.findElement(By.cssSelector("#setting_input_nickname")).sendKeys("newApple");
//点击修改按钮
webDriver.findElement(By.cssSelector("#setting_submit_nickname")).click();
Thread.sleep(1000);
//再次获取昵称,判断是不是修改后的昵称名
String actualNickName = webDriver.findElement(By.cssSelector("#settings_nickname")).getText();
Thread.sleep(1000);
String exceptNickName = "newApple";
Assertions.assertEquals(actualNickName, exceptNickName); // 断言
System.out.println("昵称修改成功!");
}
2.9 退出测试
场景:登录后,点击退出按钮,跳转回登录界面,退出成功。
public class back {
@ParameterizedTest
@CsvSource(value = "apple1, 123456")
void LoginOut1(String username, String password) throws InterruptedException, IOException {
WebDriver webDriver = new ChromeDriver();
//1-登录
webDriver.get("http://8.130.40.249:8080/sign-in.html");
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
webDriver.findElement(By.cssSelector("#username")).sendKeys(username);
webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
// 点击提交
webDriver.findElement(By.cssSelector("#submit")).click();
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.MINUTES);
//2-点击我的帖子
webDriver.findElement(By.cssSelector("#index_nav_avatar")).click();
Thread.sleep(1000);
//点击退出按钮
webDriver.findElement(By.cssSelector("#index_user_logout")).click();
Thread.sleep(2000);
//获取当前的url地址
String expect = "http://8.130.40.249:8080/sign-in.html";
String actual = webDriver.getCurrentUrl();
//判断是否跳转到登录界面
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
Assertions.assertEquals(expect, actual);
}
}
3 性能测试
对登录界面进行性能测试
3.1 VUG录制脚本
{
web_add_auto_header("Pragma",
"no-cache");
web_add_auto_header("User-Agent",
"Post");
web_custom_request("wdinfo.php",
"URL=http://qurl.f.360.cn/wdinfo.php",
"Method=POST",
"Resource=0",
"RecContentType=application/octet-stream",
"Referer=",
"Snapshot=t1.inf",
"Mode=HTML",
"EncType=application/octet-stream",
"BodyBinary=\\x0E\\x06$!\\x01\\x08jw\\xA4\\x10\\x00\\x00\\x05\\x00M\\xA6\\xD8\\x7F\\x06\\xDD\\x11?Y\\x82aD\\x02\\xF8\\xBB/\\x8Fe&\\xAF\\xCEX\\x9A\\x1F\\xB8\\x9D}\\xFCK\\x9E\\xDDf\\x87\\xFA\\xFA,z\\xC6!\\xBE\\x97*0%\\x96r\\xE3\\xF8\\xF46\\x13\\x80is\\xF0\\x11\\xB8\\x8DL\\x8DT\\xF6\\xA3D\\x99\\xA70\"\\x7F\\xD1\\xFCm\\xD1\\xEB\\xAF\\x08\\xD0E'\\x1FO\\x9E\\xE7\\xB8\\xBA\\x8B\\xB7\\xC4\\x8C\\xA7((\\x0F,\\x00%ud\\x16\\xAD\\xAAg\\xCD\\xCB\\x9E\\x82/?\\x8F%v\\xE4}"
"\\x97\\xB4\\x0C\\x10N\\xB9\\x933M\\xF7\\x1F\\xA2\\x00\\xD4\\xC0\\xDF\\xC2t\\xED\\xEE\\xAC\\xE7M!\\xEB*\\xB4I\\x83O\\xBE\\xF0\\xB8\\x80\\x1E\\xFA+\\xA7\\xEFH.\\xC8x\\xF4\\xB7\\x9F\\x86Kr\\xF0\\x91Fj\\xD2a\\xD8\\x9F\\x9C\\xF4\\xCA\\xC9\\xC5\\xA5\\xBBe\\x03N\\xFAP'I\\x993\\xBB\\x11];\\xB4\\xDDLt~|}\\xD3>\\xF4{\\x13U\\xAD\\xC7\\xCF\\xBE\\xBA\\x9E\\x81&r\\xF24fV\\x1E\\xF8\\xF5 "
"\\xBD\\x8F\\x02\\xE1x*\\x8B\\x9B'\\xE6\\xCBu\\x8F\\xCE\\x0B\\xBD\\xFD\\xFC\\xEDlU\\xF6\\xC1\\xE8\\xB2s\\x84kr\\xF2hJ\\xDBFTG\\xE1[\\x05j\\xF6\\x9Cq\\xE6\\x8A]\\x02\\xB0\\x1F@\\xBE\\xAF\\xAB\\xB5\\x01\\x1D\\xE4\nq\\x00:\\xC6\\xEE\\xDD\\xE2\\xA1J*\\xC1!c3\\xD5GX\\xEF+\\x9F\\xF9\\xF9G09\\xE6\\x04\\x18\\x05\\xE9\\x92<\"\\xE1\\x08M\\xD6,\\xEB'\\xCF\\xC6\\xD5M\\x14\\xFD_F2\\xC9\\xF1\\x98\\xA0b-2<=\\xC9Qk!\\x98an}\\x05\\xE9\\xD2\\x02\\x03\\x9EoSPX<4\\xC0\\xD1At\nO\\xAF\\xEB2\\x9C\\xEB\\x98\\xBD\\xCC\\xFE"
",\\xC6r\\x10\\x9D\\x1C&|\\xF8\\xE5\\x94\\xE8\\xB7\\x9Av\\xD69Z\\x94J\\x89 \\xA86\\xB5f\\x9C\\x02\\xA6\\xEBr\\x9AbC\\\\\\xDD\\xC7W\\xAE}\\xC0\\x17\\x8F\\xED\\x19F\\xCF\\x92\\xD1\\xA3H\\xF4:G\\xE6\\xC7\\xAE\\x95\\xEEn\\xC3\\xE6]\\x92\\x92|\\x99}:@\\xF4\\xC9d \\xA1/\\xB8\\x97\\x8B \\xDFN\\xEE^\\x88\\xCDj\\xC0\\xC9\\x9E\\x8A\\xBD\\xA2",
LAST);
web_custom_request("wdinfo.php_2",
"URL=http://qurl.f.360.cn/wdinfo.php",
"Method=POST",
"Resource=0",
"RecContentType=application/octet-stream",
"Referer=",
"Snapshot=t2.inf",
"Mode=HTML",
"EncType=application/octet-stream",
"BodyBinary=\\x1E\n\\x01\\x02\"$\\x00\\x00\\x02 \\xDD\\xACk\\xE2x\\xCE4\\xA4D\\xDEx\\x0Fo-\\x06\\xEE\\x00\\x00\\x00\\x05\\\\e\\x9D\\xE9\\xB92\\xB9\\\\\\xFCu'\\x0B\\xAF\\x08\r\\xF75\\xEBr\\x82\\x80\\x8B\\x8F\\xD0\\x16ufl\\x06\\x93k\\xA2~\\x9AI0\r\\xB3\\xBB\\x19G\\x96\\xD4\\xFDb\\xA8c\\xF9\\xE4]^\\x1C5\\x87\\xCD\\xB2F\\xC0\\xE0\\x973\\x01 \\x94\\xDD\\x18\"~<\\xE47v\\x95+\\xB8\\xF8\\x10tl\\x8C\\x8D\\xAC\\x89\\xEE\\x11\\xFB\\xCC\\xFF\\xA1\\xBF)\\xE1fQ3\\x18"
"{D-\\xFF\\xE1\\x14\\x94\\xB1\\xAB\\xD6\\x00\\xE7\\xBE\\xCECD\\x14\\xB9\\xD7\\xDD\\x8F\\xA33\\x8D\\x87\\xA3\\x06\\xF3\\x1B\\xE0F\\xAD\\xC6\\x02\\xCD\\xE6<(\\x89*\\xF5G\\xA8\\xD2\\xA6\\xC8u\\xEBWQ\\xDE:\\xB3z_\\x1E\\xA0b&\\xC3\\x0F\\xFE$\\x8D\\xAE%\\xDB\\x89\\xDFR\\x08~\\x04\\x8C,\\xC0\\x86\\xE0\\x95\\x915\\x03wU\\x80\\xF7\\x84\\x9B\\xEB(\\xE9>\\xE0\\x9F\\x99^y\\xCA\\xCF5\\xB9\\x1E\\xAB!k#\\x85\\xFBhl\\x92x\\xB2\\xA0)\\xC9\\x1DN+vhL\\xF0m\\x1F\\xB9\\x9A\\x7F\"\\xC70\r"
"\\xF8a\\x06\\x84\\x0C\\x19\\x02S\\xE8j\\x08\\xE7\\xFE\\x0EPm\\x93\\x1Cr\\xC9\\xAE\\x91\\x0C\\x17p(\\xB6q\\xA0\\xF8@ [\\xF0\\x05\\xA2\\xA5\\x05[\\x9Bd\\xD7\\xAA\\xA7Z\\xCC\\xF38\\x9D\\xA0\\x88\\xF2\\xB4k\\xA0\\x8AY\\xCBN\\xC8\\xF2\\x89\\x94n\\xEFkiV\\xD8\\x90\\x99\\x93\\xA0\\xBD\\xB4.p\\x9Ca@\\xB4\\x1D\\xBA\\xF84c@\\x9D\\x13\\xB0\\x08\\x95u\\xDEqk\\xC7\\x18I\\xB5\\x86)i\\xDD\\xB8?\\xD30q\\x0E\\xD6.aTX\\xA7[RD\\xC8\\xA8sH\\xFB?\\xE2\\xDC<^\\xDD\\xEF\\xA64\\x99\\x193\\xB1\\xE9 \\x87\\x94\\xB1LV&"
"\\xF9Z\\\\\\x95\\xE2\r\\x9A\\x9E\\x0B\\x16\\xC2\\xE3\\x9F\\xC9Hs\\xD1\\xDF\\x95M\\xC66\\x11}\\x81\\xD2[bWa\\x87\\x13\\xCB\\xD0\\xA5V\\x05\\x0C%\\x8C)\\xA4\\x91\\x05nH\\xC2w3o9W\\x7F\\xA0Sb\n\rp\\xDA\\x8D\\xC5\\x8F#\\xC3\\xD7:\\x9D\\x99\\xC7\\xE4\tpd]J\\xF4\\x06\\x8F\\x8DS\\xC8\\x88!\\x9C\t\\x8D\\xDD8\\xCD\\x1FH\\xFF\\x0C\\xE2\\xC6\\xCF\\xC7\\xC4\\x0F\\xDCaT\\xAE\\x84\\xB1\\\\\\xAD\\x1A\\x97\\x08\\xAB\\xC4\\xF3\\xDCp\\xEB.\r\\xF9w\\xFENK\\x90\\xBB\\x87d\\x00R\\xE2~\\x8F\\xCC]rD\\xA5\\x9F"
"[\\xCA\\x11\\xC6\\xBE\\xB2\\xAC \\xCD\\xD4f\\xAF\\xC2\\x9C\\xBBT!\\x89\\x7FW`k\\xBBQRj\\x85^\\xD0}M\\xA1",
LAST);
web_custom_request("wdinfo.php_3",
"URL=http://qurl.f.360.cn/wdinfo.php",
"Method=POST",
"Resource=0",
"RecContentType=application/octet-stream",
"Referer=",
"Snapshot=t3.inf",
"Mode=HTML",
"EncType=application/octet-stream",
"BodyBinary=\\x1E\n\\x01\\x02\"$\\x00\\x00\\x02\\x00\\xF3^\\xF4(\\x9F\\x1BQZtA\\xCCg\\x1D\\xFAu\\xB6\\x00\\x00\\x00\\x05]\\xDCe\\x1F\\xF2\\xE2\\x86\\xEFb\\xA4>\\x86f\\xE8\n\\xC5\\xE6\\x1C\\xF6\\x9AWS\\xAAj\\x85A\\x83_\\x00\\x85\\xDA\\xF8m\\xC9f\\xCE\\xD0m\\x0Ec\\xFA\\x91\\x03p),\\x8EYx\\xFCZ\\xEBB*a\\xA4P\\xE9\\xC1\\xC0\\x96\\xAD@\\x89`c\\xBF\\xED:\\xFE\\x1D\\x85\\x10=\\x8DS\\xE9\\xDFTZ\"&\\xDA\\x9AQ3\\x82'\\xEC\\xED\\x87\\x18\\xB8\\x87\\xA9\\x08\\xB2\\xC0\\x00\\xFF\\x85\\x8Fu]"
"\\xCA`\\xB0l\\xCEV\\xBD\\xD3\\x9B\\xF3\\x18\\xDF\\xE8ME?\\x18\\x10\\xFC\\xE8\\xE2\\x7F\\xC5\\x10D\\x86!U\\x87\\xB3\\x8D\\xCD\\xA6\\xC6T\\x8C\\xC1\\xC7\\x11\\xA7Q\\xCB\\xBFz\\x10\\xFF\\xA1t\\x8F=\\x82\\xF2S\\xCAdW\\xB9\\x17\\xF5m\\x89\\xD3\\x0B\\x89\\x04\\xC4\\x0B\\xB0\\xC1\\x96\\xBB\\xFE\\x92q*C\\x93\\xE9\\xC9\\xF7\\xBB\\xFF\\xF3o\\xDE\\xFA\\xD0\\x04\"w\\x89!\\xAE\"!F.\\xFA\\xA9\\xB3\\x12\\x86\\x80\\xAF\\xC0]\\x15\\xBA\\xA6\\xBD\\x06\\xE4r\\x15p\\x15^\\xA9\\x86\\xBA\\x04\\x8A\\xF3|"
"\\xC5\\xE4\\xD1\\x1BR\\xB3\\xB5\\xC8J:C\\x01\\x95\\xE2\\xB3\\x1E\\x86\\xA9,\\x0E\\xDD\\xFA\\xF6M\\x87p\\x08p\\xA96\\xE1\\xE3]I\\xE0u\\xC8\\xF7\\xC1\\x94\\x04\\x85\\xB88\\xB0\\xF4\\x16p\\x1E\\xCC\\x0F1\\x0E\\xC0\\xADs\\x93\\x0Coe\\x83Y)Z\\x9B\\xDF2(\\x19\\xEA\\x8D\\xCE\\xE7\\xAF4LN[\\xE3\\xFF5U\\xB5\\x11\\x9B{\\x1C\\x1EA\\x9B\\xF6\\x1A)y\\xDA\\xE00>O\\xA4{\\xCD\\xBB\\xBF\\xB6\\x9AB\\x00\\xB1\\xB5\\x83K\\xAE\\xCB\\x1B\\x08\\x15\\x8A\\xA5\\x1FID7pLk\\xC1 \\x10\\xE5\\xD6F\\xA0\\xDEG"
"(w\\x8C\\xC1\\xD4\\xDE\\xAB\\x94\\xD0M\\xC4G\\xDB\\x1DB\\xFD\\xD9\\x11qz\\xCB\\x84-\\xC1\\xDDuTP\\xEC\\xBD\\x13;6g0\\x8D\\xED\\xFC\r'\\xDA\\xDB\\xA5^\\xEF\\x11\\xE26\\xDF/O\\\\\\x14.\\x86\\x9C\\xC5a\\xB3\\xDBl\\xC22\\x9B3\\xCF\\x8D\\xB7\\xD2:\\x10\\x88\\xC7\\xB3 \\x89\\x1A4\\xBE\\xED\\xFE\\x82\\xA7\\xC2\\x1D\\xAE\\x9A\\xBFB\\x90\\x13_\\x0B\\x0B\\xEE\\x91~\\xBC\\xB6DF\\x04\\x8B\\xD9_\\x86\\xD0\\xC4VES\\x8Ax-c\\xAEe\\xC4|TG\\xE9\\xBB\\xDF\\x9F[\\x07\\x8EU\\x0CU2+\\xB3\\xFD2\\xDF\\xE3\\xE3\\x0Bnu"
">\\xDA\\xDF\\x9A\\xD0\\xDA\\xCA",
LAST);
web_revert_auto_header("Pragma");
web_add_auto_header("User-Agent",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.6045.9 Safari/537.36 QIHU 360EE");
web_add_auto_header("Accept-Encoding",
"gzip, deflate");
web_add_auto_header("Accept-Language",
"zh-CN,zh;q=0.9");
web_add_header("If-None-Match",
"W/\"5fc4655e-12b0c\"");
web_url("young_mode.html",
"URL=http://browser.360.cn/conf/young_mode.html",
"Resource=0",
"RecContentType=text/html",
"Referer=",
"Snapshot=t4.inf",
"Mode=HTML",
LAST);
web_add_header("Accept",
"*/*");
web_add_header("Origin",
"http://8.130.40.249:8080");
web_add_auto_header("User-Agent",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.6045.9 Safari/537.36");
web_add_header("X-Requested-With",
"XMLHttpRequest");
//插入事务
lr_start_transaction("login");
web_submit_data("login",
"Action=http://8.130.40.249:8080/user/login",
"Method=POST",
"RecContentType=application/json",
"Referer=http://8.130.40.249:8080/sign-in.html",
"Snapshot=t5.inf",
"Mode=HTML",
ITEMDATA,
"Name=username", "Value=cll", ENDITEM,
"Name=password", "Value=123", ENDITEM,
EXTRARES,
"Url=info", "Referer=http://8.130.40.249:8080/index.html", ENDITEM,
"Url=../board/topList", "Referer=http://8.130.40.249:8080/index.html", ENDITEM,
"Url=../message/getAll", "Referer=http://8.130.40.249:8080/index.html", ENDITEM,
"Url=../message/getUnreadCount", "Referer=http://8.130.40.249:8080/index.html", ENDITEM,
"Url=../article/getAllByBoard", "Referer=http://8.130.40.249:8080/index.html", ENDITEM,
"Url=../board/getById?id=1", "Referer=http://8.130.40.249:8080/index.html", ENDITEM,
"Url=../article/getAllByBoard?boardId=1", "Referer=http://8.130.40.249:8080/index.html", ENDITEM,
"Url=../board/getById?id=2", "Referer=http://8.130.40.249:8080/index.html", ENDITEM,
"Url=../article/getAllByBoard?boardId=2", "Referer=http://8.130.40.249:8080/index.html", ENDITEM,
"Url=../board/getById?id=3", "Referer=http://8.130.40.249:8080/index.html", ENDITEM,
"Url=../article/getAllByBoard?boardId=3", "Referer=http://8.130.40.249:8080/index.html", ENDITEM,
"Url=../article/getAllByBoard?boardId=5", "Referer=http://8.130.40.249:8080/index.html", ENDITEM,
"Url=../board/getById?id=5", "Referer=http://8.130.40.249:8080/index.html", ENDITEM,
LAST);
lr_end_transaction("login", LR_AUTO);
return 0;
}
脚本录制通过
3.2 使用Controller
3.2.1 创建性能测试场景
一次初始化5个用户,每隔1秒初始化一个虚拟用户
设置虚拟用户数量10个,每隔1秒启动5个用户
运行时间设置3分钟
退出所有用户,每隔1秒退出1个用户
3.2.2点击运行,启动场景
运行过程截图:
3.3 生成测试报告
点击率
吞吐量:
点击数越多,要处理的请求数量越多