发布时间:2025-12-10 11:47:46 浏览次数:7
实现一个网页版的博客系统,提供了一个技术文章论坛,同时也提供了用户之间在线交流的平台。
网页博客系统支持以下核心功能:
online 好友聊天室支持以下核心功能:
额外扩展功能:
1. 文章评论功能.2. 文章点赞功能.3. 文章保存草稿功能.4. 用户找回密码功能.5. 用户相互关注功能,附带粉丝列表,关注列表.6. 用户个⼈中心:支持修改密码、修改昵称(非登录名)、修改密保等功能.7. 使用多线程(使用线程池优化)实现文章定时发布功能.8. 使用多线程(使用线程池优化)实现用户多次登录,账号冻结的业务.9. 使用 MultipartFile 实现上传头像,使用 WebMvcConfigurer 配置自定义资源映射实现头像展示.10. 手动实现密码加盐算法,提高用户信息安全性.11. 使用 hutool 工具,实现了登录时图片验证码功能,增加了系统的安全性.12. 使用 HandlerInterceptor 实现了统一登录拦截器.13. 使用 ResponseBodyAdvice 实现了统一数据格式返回.整个 Web 项目分为以下页面
客户端输入用户名、密码、验证码,后端首先检验验证码受否正确,然后通过 Spring + MyBatis 进行数据库的查询操作校验用户的账号和秘密是否正确,若正确则将 Session 信息持久化到 Redis 上并跳转到博客列表页,若错误则用弹窗进行提示。
客户端输入账号和密码,增加用户,通过 MySQL 将用户信息进行持久化保存.
服务器通过 Spring + MyBatis 进行信息的增添.
客户端输入找回账号、真实密码、身份证号作为修改密码的前置步骤,前置步骤验证通过后,服务器通过 Spring + MyBatis 进行数据库的修改密码.
面向任意用户,博客列表支持分页功能,可以在该界面访问所有用发布的博客以及访问量点赞信息,并且可以点击 “查看全文” 查看博客详细信息.
服务器通过 Spring + MyBatis 进行数据库的查询操作,查询所有文章.
博客详情页可以,查看博客的详细信息以及作者信息,已登录用户可以进行关注,发表评论,删除评论.
服务器通过 Spring + MyBatis 进行数据库的查询操作,查询当前访问的文章和作者信息.
面向当前登录用户. 该页面用户可以填写标题和正文,最后点击发布按钮进行发布博客; 用户也可以选择定时发布博客,让博客在指定时间发布; 用户也可以选择先不发布博客,保存草稿.
服务器通过 MySQL 保存用户发布的博客信息.
面向当前登录用户. 该页面可以进行对之前发布的页面进行编辑操作,修改完后点击发布博客即可修改文章; 用户也可以选择定时发布博客,让博客在指定时间发布; 用户也可以选择先不发布博客,保存草稿.
服务器通过 Spring + MyBatis 对数据库进行相应的修改操作。
面向当前登录用户. 该页面可以对之前保存的文章草稿进行修改和删除.
服务器针对用户的以上操通过 Spring + MyBatis 进行相应的增删改查操作.
面向当前登录用户. 可以对当前登录用户进行信息修改.
服务器针对用户的以上操通过 Spring + MyBatis 进行相应的增删改查操作.
个人:
他人:
面向当前登录用户. 该页面会展示用户的个人发布的所有博客,若是自己的主页可以对这些博客进行查看详情,修改,删除等功能,若是他人主页可以查看文章详情,并且可以查看粉丝列表和关注列表.
服务器针对用户的以上操通过 Spring + MyBatis 进行相应的增删改查操作.
面向已登录的用户. 该页面通过消息推送机制,展现在线与离线好友(相互关注),可以与好友进行聊天,消息通过 WebSocket 进行实时推送.
a)输入异常的账号、密码、验证码
预期结果:弹窗对应提示
实际结果如下:
b)输入正常的账号和密码
预期结果:跳转到用户主页
实际结果如下:
a)输入异常的账号、密码、确认密码
预期结果:对应的弹窗提示
实际结果如下:
b)输入正常的账号、密码、确认密码
预期结果:弹窗提示是否跳转到登录页面
实际结果如下:
a)异常填写账号、密保信息、密码
预期结果:对应的弹窗提示
实际结果如下:
b)输入正确的信息
预期结果:弹窗提示密码找回成功,是否跳转到登录页.
实际结果如下:
a)点击对应博客弹出对应的博客详情
b)分页功能测试
预期结果:上一页,下一页,首页,末页均有边界处理
实际结果如下:
a)预期结果:点击点赞按钮,标识已点赞,再点一次取消点赞
实际结果如下:
b)预期结果:评论后在评论区显示评论气泡
实际结果如下:
c)预期结果:点击删除评论,进行信息删除,若不是自己的评论(作者除外),无法删除
实际结果如下:
a)博客列表显示
b)粉丝列表显示
c)关注列表显示
a)预期结果:点击删除草稿,进行弹窗提示,若确认,则删除草稿。
实际结果如下:
a)预期结果:点击发布博客,进行对应弹窗提示,确认后,回到主页即可看到博客 .
实际结果如下:
b)预期结果:点击定时发布功能,设置时间为1分钟后发布(若没设置时间,则进行弹窗提示),并在1分钟后在主页观察到博客。
实际结果如下:
c)预期结果:点击保存草稿后,在草稿列表显示
实际结果如下:
a)修改头像后,在界面实时展示
a)预期结果:登录后相互关注的好友可以观察到对方上线消息.
实际结果如下:
b)预期结果:双方互发消息,消息气泡在对应一侧,并且消息及时推送
c)预期结果:输入框输入消息,点击发送按钮后,清空消息框
实际结果如下:
单例驱动: 自动化程序中会很频繁的使用驱动,如果频繁的创建和销毁开销还是比较大的,因此我们可以使用一种懒汉模式的加载方式去加载驱动,这样既能保证驱动不会频繁创建(程序运行过程保持单例),又能减轻程序刚开始启动时的系统开销(只有用到驱动的时候才去加载他),其他类如果需要驱动直接继承该类即可.
屏幕截图: 有的时候我们测试用例执行出错了,我们需要查看当时网页出现的情况,那么就需要使用屏幕截图来排查问题.
具体的,可以使用驱动的 getScreenshotAs 方法去保存屏幕截图,在每一个测试case执行完后进行一次屏幕截图,并将截图保存到一个路径下,文件名以当时时间进行组织(防止保存屏幕截图出现覆盖情况),那么就可以在AutoTestUtils类下加上屏幕截图的方法,方便其他类调用.
创建一个类(自定义名为 RegTest)继承 AutoTestUtils,得到驱动,首先测试登录页面是否正常打开,接着找几个典型的 case 使用参数化注解进行测试注册功能即可,最后进行相应弹窗处理,最后进行屏幕截图.
import com.common.AutoTestUtils;import org.junit.jupiter.api.*;import org.junit.jupiter.params.ParameterizedTest;import org.junit.jupiter.params.provider.CsvSource;import org.openqa.selenium.Alert;import org.openqa.selenium.By;import org.openqa.selenium.WebDriver;import org.openqa.selenium.WebElement;import org.openqa.selenium.edge.EdgeDriver;import java.io.IOException;@TestMethodOrder(MethodOrderer.OrderAnnotation.class)public class RegTest extends AutoTestUtils {//获取到驱动private static EdgeDriver driver = AutoTestUtils.getDriver();/*** 打开网页*/@BeforeAllpublic static void openWeb() {driver.get("http://43.139.193.116:8080/reg.html");}/*** 验证网页正常打开*/@Test@Order(1)public void webAppear() throws IOException {driver.findElement(By.cssSelector("#username"));driver.findElement(By.cssSelector("body > p.login-container > p > p:nth-child(4)"));driver.findElement(By.xpath("//*[@id=\"submit\"]"));driver.findElement(By.xpath("/html/body/p[2]/p"));//屏幕截图getScreenShot(getClass().getName());}/*** 异常测试注册功能* @param username* @param password*/@ParameterizedTest@CsvSource({"zhangsan, 123, 123", "aaa, 123, 1233"})@Order(2)public void regFunTest(String username, String password, String confirmPassword) throws InterruptedException, IOException {//拿到元素WebElement inputUsername = driver.findElement(By.cssSelector("#username"));WebElement inputPassword = driver.findElement(By.cssSelector("#password"));WebElement inputconfirmPassword = driver.findElement(By.cssSelector("#password2"));WebElement button = driver.findElement(By.cssSelector("#submit"));//先清除输入框inputUsername.clear();inputPassword.clear();inputconfirmPassword.clear();//输入用例inputUsername.sendKeys(username);inputPassword.sendKeys(password);inputconfirmPassword.sendKeys(confirmPassword);//提交button.click();//处理弹窗Thread.sleep(100);driver.switchTo().alert().accept();//屏幕截图getScreenShot(getClass().getName());}}创建一个类(自定义名为 LoginTest)继承 AutoTestUtils 类,获取驱动,之后选取典型 case 使用参数化注解对异常、正常登录分别进行测试,进行相应弹窗处理,最后进行屏幕截图.
import com.common.AutoTestUtils;import org.junit.jupiter.api.*;import org.junit.jupiter.params.ParameterizedTest;import org.junit.jupiter.params.provider.CsvSource;import org.openqa.selenium.Alert;import org.openqa.selenium.By;import org.openqa.selenium.edge.EdgeDriver;import java.io.IOException;@TestMethodOrder(MethodOrderer.OrderAnnotation.class)public class LoginTest extends AutoTestUtils {//获取驱动private static EdgeDriver driver = AutoTestUtils.getDriver();/*** 打开网页* @BeforeAll 标识在所有测试用例执行之前执行依次。*/@BeforeAllprivate static void openWeb() {driver.get("http://43.139.193.116:8080/login.html");}/*** 检测登录页面能否正常打开*/@Test@Order(1)public void elementsAppear() throws IOException {driver.findElement(By.cssSelector("#username"));driver.findElement(By.cssSelector("#checkpassword-img"));driver.findElement(By.cssSelector("body > p.login-container > p"));driver.findElement(By.cssSelector("body > p.login-container > p > p.assist > a:nth-child(2)"));//屏幕截图getScreenShot(getClass().getName());}/*** 检测登录异常测试* @param username* @param password* @param checkPassword 验证码* Ps: 万能验证码为 chenyikang*/@ParameterizedTest@CsvSource({"adm* , 1234, chenyikang", "daf, 11, chenyikang", "&*^% , 123, aaa"})@Order(2)public void loginAbnormalTest(String username, String password, String checkPassword) throws InterruptedException, IOException {//清除用户名、密码框、验证码driver.findElement(By.cssSelector("#username")).clear();driver.findElement(By.cssSelector("#password")).clear();driver.findElement(By.cssSelector("#checkpassword")).clear();//输入账号、密码、验证码driver.findElement(By.cssSelector("#username")).sendKeys(username);driver.findElement(By.cssSelector("#password")).sendKeys(password);driver.findElement(By.cssSelector("#checkpassword")).sendKeys(checkPassword);driver.findElement(By.cssSelector("#submit")).click();//强制等待,等待弹窗Thread.sleep(100);//处理弹窗Alert alert = driver.switchTo().alert();//期望结果String expect = "用户名/密码/验证码错误";String actual = "用户名/密码/验证码错误";//实际结果(若未出现弹窗,说明不符合预期);if(alert == null) {actual = "当前页面异常";}alert.accept();//屏幕截图getScreenShot(getClass().getName());Assertions.assertEquals(expect, actual);}/*** 正常登录测试* @param username* @param password* @throws InterruptedException*/@ParameterizedTest@CsvSource({"zhangsan, 123"})@Order(3)public void loginNormalTest(String username, String password) throws InterruptedException, IOException {//清除用户名、密码框、验证码driver.findElement(By.cssSelector("#username")).clear();driver.findElement(By.cssSelector("#password")).clear();driver.findElement(By.cssSelector("#checkpassword")).clear();//输入账号、密码、验证码driver.findElement(By.cssSelector("#username")).sendKeys(username);driver.findElement(By.cssSelector("#password")).sendKeys(password);driver.findElement(By.cssSelector("#checkpassword")).sendKeys("chenyikang");driver.findElement(By.cssSelector("#submit")).click();//屏幕截图getScreenShot(getClass().getName());//登录成功需要返回登录界面//点击注销driver.findElement(By.cssSelector("body > p.nav > a:nth-child(9)")).click();//处理弹窗//强制等待,等待弹窗Thread.sleep(100);driver.switchTo().alert().accept();//等待处理完成Thread.sleep(100);}}创建一个类(自定义名为 fundPasswordTest )继承 AutoTestUtils 类,获取驱动,首先验证页面是否能正常显示,接着找几个典型的 case 使用参数化注解对其进行测试,进行相应弹窗处理,最后进行屏幕截图.
import com.common.AutoTestUtils;import org.junit.jupiter.api.*;import org.junit.jupiter.params.ParameterizedTest;import org.junit.jupiter.params.provider.CsvSource;import org.openqa.selenium.By;import org.openqa.selenium.edge.EdgeDriver;import java.io.IOException;@TestMethodOrder(MethodOrderer.OrderAnnotation.class)public class fundPasswordTest extends AutoTestUtils {//获取驱动private static EdgeDriver driver = AutoTestUtils.getDriver();/*** 打开页面*/@BeforeAllpublic static void openWeb() {driver.get("http://43.139.193.116:8080/fund_password.html");}/*** 验证页面正常打开*/@Test@Order(1)public void WebAppear() throws IOException {driver.findElement(By.cssSelector("#ps"));driver.findElement(By.cssSelector("#realname"));driver.findElement(By.cssSelector("#submit"));driver.findElement(By.xpath("/html/body/p[2]/p"));//屏幕截图getScreenShot(getClass().getName());}/*** 异常找回密码测试* @param username* @param realname* @param id* @param newPassword* @param password*/@ParameterizedTest@CsvSource({"wu, zhangsan, 610, 123, 123", "zhangsan, lisi, 610, 123, 123","zhangsan, zhangsan, 611, 123, 123", "zhangsan, zhangsan, 610, 123, 12234"})@Order(2)public void fundPasswordFunExceptionTest(String username, String realname,String id, String newPassword, String password) throws InterruptedException, IOException {//先清除输入框driver.findElement(By.cssSelector("#username")).clear();driver.findElement(By.cssSelector("#realname")).clear();driver.findElement(By.cssSelector("#idcard")).clear();driver.findElement(By.cssSelector("#password1")).clear();driver.findElement(By.cssSelector("#password2")).clear();//输入driver.findElement(By.cssSelector("#username")).sendKeys(username);driver.findElement(By.cssSelector("#realname")).sendKeys(realname);driver.findElement(By.cssSelector("#idcard")).sendKeys(id);driver.findElement(By.cssSelector("#password1")).sendKeys(newPassword);driver.findElement(By.cssSelector("#password2")).sendKeys(password);//提交driver.findElement(By.cssSelector("#submit")).click();//处理弹窗Thread.sleep(100);driver.switchTo().alert().accept();//屏幕截图getScreenShot(getClass().getName());//处理完弹窗若还能发现页面元素,说明异常处理成功String expect = "找回密码";String actual = driver.findElement(By.cssSelector("body > p.login-container > p > h3")).getText();Assertions.assertEquals(expect, actual);}/*** 正常找回密码* @param username* @param realname* @param id* @param newPassword* @param password*/@ParameterizedTest@CsvSource("zhangsan, zhangsan, 610, 123, 123")@Order(3)public void fundPasswordFunNormalTest(String username, String realname,String id, String newPassword, String password) throws InterruptedException, IOException {//先清除输入框driver.findElement(By.cssSelector("#username")).clear();driver.findElement(By.cssSelector("#realname")).clear();driver.findElement(By.cssSelector("#idcard")).clear();driver.findElement(By.cssSelector("#password1")).clear();driver.findElement(By.cssSelector("#password2")).clear();//输入driver.findElement(By.cssSelector("#username")).sendKeys(username);driver.findElement(By.cssSelector("#realname")).sendKeys(realname);driver.findElement(By.cssSelector("#idcard")).sendKeys(id);driver.findElement(By.cssSelector("#password1")).sendKeys(newPassword);driver.findElement(By.cssSelector("#password2")).sendKeys(password);//提交driver.findElement(By.cssSelector("#submit")).click();//处理弹窗Thread.sleep(100);driver.switchTo().alert().accept();//屏幕截图getScreenShot(getClass().getName());Thread.sleep(100);String expect = "登陆";String actual = driver.findElement(By.cssSelector("body > p.login-container > p > h3")).getText();Assertions.assertEquals(expect, actual);}}创建一个类(自定义名为 PersonalInfoTest)继承 AutoTestUtils,得到驱动,对基础信息、密保信息、修改密码使用典型 case 进行测试,进行相应弹窗处理,最后进行屏幕截图.
import com.common.AutoTestUtils;import org.junit.jupiter.api.*;import org.junit.jupiter.params.ParameterizedTest;import org.junit.jupiter.params.provider.CsvSource;import org.junit.jupiter.params.provider.ValueSource;import org.openqa.selenium.Alert;import org.openqa.selenium.By;import org.openqa.selenium.edge.EdgeDriver;import java.io.IOException;@TestMethodOrder(MethodOrderer.OrderAnnotation.class)public class PersonalInfoTest extends AutoTestUtils {private static EdgeDriver driver = AutoTestUtils.getDriver();@BeforeAllpublic static void openWeb() throws InterruptedException {// //方式一:单元测试// driver.get("http://43.139.193.116:8080/login.html");// driver.findElement(By.cssSelector("#username")).clear();// driver.findElement(By.cssSelector("#password")).clear();// driver.findElement(By.cssSelector("#checkpassword")).clear();// //输入账号、密码、验证码// driver.findElement(By.cssSelector("#username")).sendKeys(AppValues.USERNAME);// driver.findElement(By.cssSelector("#password")).sendKeys(AppValues.PASSWORD);// driver.findElement(By.cssSelector("#checkpassword")).sendKeys(AppValues.CODE);// driver.findElement(By.cssSelector("#submit")).click();// Thread.sleep(100);// driver.findElement(By.cssSelector("body > p.nav > a:nth-child(5)")).click();//整体测试//此时已经有 session 会话了,直接进入即可driver.get("http://43.139.193.116:8080/myinfo.html");}/*** 验证页面正常打开*/@Test@Order(1)public void webAppear() throws IOException {driver.findElement(By.cssSelector("#photo"));driver.findElement(By.cssSelector("#gitee"));driver.findElement(By.cssSelector("#submit"));driver.findElement(By.cssSelector("body > p.login-container > p > p:nth-child(12)"));//屏幕截图getScreenShot(getClass().getName());}/*** 修改基础信息测试* @param nickname*/@ParameterizedTest@ValueSource(strings = {"123", "xiaozhang", "&*^%$", "小张"})@Order(2)public void basicInfoTest(String nickname) throws InterruptedException, IOException {//清除输入框driver.findElement(By.cssSelector("#nickname")).clear();//输入信息driver.findElement(By.cssSelector("#nickname")).sendKeys(nickname);//提交driver.findElement(By.xpath("/html/body/p[2]/p/p[3]/button")).click();//处理弹窗Thread.sleep(100);driver.switchTo().alert().accept();//屏幕截图getScreenShot(getClass().getName());}/*** 修改密保信息测试*/@ParameterizedTest@CsvSource({"132, &*^, 610", "$$#@^7., &$(#)+, 610", "123, zhangsan, 610"})@Order(3)public void SecurityInfoTest(String username, String realname, String id) throws InterruptedException, IOException {//清除输入框driver.findElement(By.cssSelector("#password")).clear();driver.findElement(By.cssSelector("#realname")).clear();driver.findElement(By.cssSelector("#idcard")).clear();//输入信息driver.findElement(By.cssSelector("#password")).sendKeys(username);driver.findElement(By.cssSelector("#realname")).sendKeys(realname);driver.findElement(By.cssSelector("#idcard")).sendKeys(id);//提交driver.findElement(By.xpath("/html/body/p[2]/p/p[6]/button")).click();//处理弹窗Thread.sleep(200);driver.switchTo().alert().accept();//屏幕截图getScreenShot(getClass().getName());//提交driver.findElement(By.xpath("/html/body/p[2]/p/p[7]/button")).click();//处理弹窗Thread.sleep(200);driver.switchTo().alert().accept();}/*** 异常密码测试1* @param oldPassword* @param newPassword* @param confirmPassword*/@ParameterizedTest@CsvSource({"134358, 123, 123", "*#&2*, 123, 123"})@Order(4)public void updatePasswordTest1(String oldPassword, String newPassword, String confirmPassword) throws InterruptedException, IOException {//清除输入框driver.findElement(By.cssSelector("#password1")).clear();driver.findElement(By.cssSelector("#password2")).clear();driver.findElement(By.cssSelector("#password3")).clear();//输入driver.findElement(By.cssSelector("#password1")).sendKeys(oldPassword);driver.findElement(By.cssSelector("#password2")).sendKeys(newPassword);driver.findElement(By.cssSelector("#password3")).sendKeys(confirmPassword);//提交driver.findElement(By.xpath("/html/body/p[2]/p/p[12]/button")).click();//处理弹窗Thread.sleep(100);Alert alert = driver.switchTo().alert();String e1 = "旧密码错误,请重新输入!";String a1 = alert.getText();alert.accept();//屏幕截图getScreenShot(getClass().getName());//断言Assertions.assertEquals(e1, a1);}/*** 异常密码测试2* @param oldPassword* @param newPassword* @param confirmPassword*/@ParameterizedTest@CsvSource({"123, adfa, 1551sf8", "123, 489, 123"})@Order(5)public void updatePasswordTest(String oldPassword, String newPassword, String confirmPassword) throws InterruptedException, IOException {//清除输入框driver.findElement(By.cssSelector("#password1")).clear();driver.findElement(By.cssSelector("#password2")).clear();driver.findElement(By.cssSelector("#password3")).clear();//输入driver.findElement(By.cssSelector("#password1")).sendKeys(oldPassword);driver.findElement(By.cssSelector("#password2")).sendKeys(newPassword);driver.findElement(By.cssSelector("#password3")).sendKeys(confirmPassword);//提交driver.findElement(By.xpath("/html/body/p[2]/p/p[12]/button")).click();//处理弹窗Thread.sleep(100);Alert alert = driver.switchTo().alert();String e1 = "新密码与确认密码不一致,请重试!";String a1 = alert.getText();alert.accept();//屏幕截图getScreenShot(getClass().getName());//断言Assertions.assertEquals(e1, a1);}/*** 正常修改密码测试* @param oldPassword* @param newPassword* @param confirmPassword*/@ParameterizedTest@CsvSource({"123, 1234, 1234", "1234, 123, 123"})@Order(5)public void updatePasswordNorTest(String oldPassword, String newPassword, String confirmPassword) throws InterruptedException, IOException {//清除输入框driver.findElement(By.cssSelector("#password1")).clear();driver.findElement(By.cssSelector("#password2")).clear();driver.findElement(By.cssSelector("#password3")).clear();//输入driver.findElement(By.cssSelector("#password1")).sendKeys(oldPassword);driver.findElement(By.cssSelector("#password2")).sendKeys(newPassword);driver.findElement(By.cssSelector("#password3")).sendKeys(confirmPassword);//提交driver.findElement(By.xpath("/html/body/p[2]/p/p[12]/button")).click();//处理弹窗Thread.sleep(100);Alert alert = driver.switchTo().alert();String e1 = "密码修改成功!";String a1 = alert.getText();alert.accept();//屏幕截图getScreenShot(getClass().getName());//断言Assertions.assertEquals(e1, a1);}}创建一个类名为 PersonalHomeTest 继承 AutoTestUtils ,得到驱动,分别对博客列表信息、粉丝列表、关注列表进行检验,最后对关注功能进行检验,进行相应弹窗处理,最后进行屏幕截图.
import com.common.AppValues;import com.common.AutoTestUtils;import org.junit.jupiter.api.*;import org.openqa.selenium.By;import org.openqa.selenium.WebElement;import org.openqa.selenium.edge.EdgeDriver;import java.io.IOException;@TestMethodOrder(MethodOrderer.OrderAnnotation.class)public class PersonalHomeTest extends AutoTestUtils {//获取驱动private static EdgeDriver driver = AutoTestUtils.getDriver();/*** 进入到个人主页中* Ps: 这里不能直接通过网址进入,需要先登录*/@BeforeAllprivate static void intoWeb() {// //先检验拦截// driver.get("http://43.139.193.116:8080/myblog_list.html?id=2");// //检验拦截后是否跳转到登录页面// String expect = "登陆";// String actual = driver.findElement(By.cssSelector("body > p.login-container > p > h3")).getText();// Assertions.assertEquals(expect, actual);//登录driver.get("http://43.139.193.116:8080/login.html");driver.findElement(By.cssSelector("#username")).clear();driver.findElement(By.cssSelector("#password")).clear();driver.findElement(By.cssSelector("#checkpassword")).clear();//输入账号、密码、验证码driver.findElement(By.cssSelector("#username")).sendKeys(AppValues.USERNAME);driver.findElement(By.cssSelector("#password")).sendKeys(AppValues.PASSWORD);driver.findElement(By.cssSelector("#checkpassword")).sendKeys(AppValues.CODE);driver.findElement(By.cssSelector("#submit")).click();}/*** 检验网页是否正常打开*/@Test@Order(1)public void webAppear() throws IOException {driver.findElement(By.cssSelector("#photo"));driver.findElement(By.cssSelector("body > p.container > p.container-left > p > p:nth-child(5) > p"));driver.findElement(By.cssSelector("body > p.container > p.container-right > p.selectInfo > span:nth-child(3)"));driver.findElement(By.cssSelector("#listInfo"));//屏幕截图getScreenShot(getClass().getName());}/*** 辅助栏检验* Ps:顺带检验关注功能*/@Test@Order(2)public void assistColumnTest() throws InterruptedException, IOException {//1.进入关注列表driver.findElement(By.cssSelector("body > p.container > p.container-right > p.selectInfo > span:nth-child(3)")).click();//找到关注元素WebElement followButton = driver.findElement(By.cssSelector("#follow-msg"));//检验关注和取关String e1 = "已关注";String a1 = followButton.getText();Assertions.assertEquals(e1, a1);//进行取关followButton.click();//等待服务器响应一会Thread.sleep(100);//屏幕截图getScreenShot(getClass().getName());//2.进入粉丝列表driver.findElement(By.cssSelector("body > p.container > p.container-right > p.selectInfo > span:nth-child(2)")).click();//进行关注driver.findElement(By.cssSelector("#follow-msg")).click();//检验是否关注成功String e2 = "已关注";Thread.sleep(500);String a2 = driver.findElement(By.cssSelector("#follow-msg")).getText();//屏幕截图getScreenShot(getClass().getName());Assertions.assertEquals(e2, a2);}}创建一个类名为 DraftListTest 继承 AutoTestUtils 类,获取驱动,在对草稿的编辑,删除功能分别进行测试,进行相应弹窗处理,最后进行屏幕截图.
import com.common.AutoTestUtils;import org.junit.jupiter.api.*;import org.openqa.selenium.Alert;import org.openqa.selenium.By;import org.openqa.selenium.edge.EdgeDriver;import java.io.IOException;@TestMethodOrder(MethodOrderer.OrderAnnotation.class)public class DraftListTest extends AutoTestUtils {//获取驱动private static EdgeDriver driver = AutoTestUtils.getDriver();/*** 进入到个人草稿页中*/@BeforeAllpublic static void intoWeb() {// //方式一:单元测试// driver.get("http://43.139.193.116:8080/login.html");// driver.findElement(By.cssSelector("#username")).clear();// driver.findElement(By.cssSelector("#password")).clear();// driver.findElement(By.cssSelector("#checkpassword")).clear();// //输入账号、密码、验证码// driver.findElement(By.cssSelector("#username")).sendKeys(AppValues.USERNAME);// driver.findElement(By.cssSelector("#password")).sendKeys(AppValues.PASSWORD);// driver.findElement(By.cssSelector("#checkpassword")).sendKeys(AppValues.CODE);// driver.findElement(By.cssSelector("#submit")).click();// driver.findElement(By.cssSelector("body > p.nav > a:nth-child(7)")).click();//整体测试//此时已经有 session 会话了,直接进入即可driver.get("http://43.139.193.116:8080/draft_list.html?id=2");}/*** 检查当前页面元素出现*/@Test@Order(1)public void webAppear() throws IOException {driver.findElement(By.cssSelector("#photo"));driver.findElement(By.cssSelector("body > p.container > p.container-left > p > p:nth-child(4) > p"));driver.findElement(By.cssSelector("#listInfo"));driver.findElement(By.cssSelector("#listInfo > p > a > p.title"));//屏幕截图getScreenShot(getClass().getName());}/*** 检验草稿功能*/@Test@Order(2)public void draftTest() throws InterruptedException, IOException {//1.检验草稿是否能打开driver.findElement(By.cssSelector("#listInfo > p > a > p.title")).click();String e1 = "这是一篇草稿";String a1 = driver.findElement(By.cssSelector("#title")).getText();Assertions.assertEquals(e1, a1);//后退driver.navigate().back();//2.检验修改草稿按钮Assertions.assertNotNull(driver.findElement(By.cssSelector("#edit")));//3.检验删除草稿功能driver.findElement(By.cssSelector("#del")).click();Alert alert = driver.switchTo().alert();Thread.sleep(100);Assertions.assertEquals("确定删除该文章?", alert.getText());//处理弹窗(取消)alert.dismiss();//屏幕截图getScreenShot(getClass().getName());}}创建一个类名为 BlogAndDraftPostTest 继承 AutoTestUtils 类,得到驱动,并对发布按钮和保存按钮进行自动化测试,进行相应弹窗处理,最后进行屏幕截图.
import com.common.AutoTestUtils;import org.junit.jupiter.api.*;import org.openqa.selenium.By;import org.openqa.selenium.edge.EdgeDriver;import java.io.IOException;@TestMethodOrder(MethodOrderer.OrderAnnotation.class)public class BlogAndDraftPostTest extends AutoTestUtils {//获取驱动private static EdgeDriver driver = AutoTestUtils.getDriver();/*** 打开当前页面*/@BeforeAllpublic static void openWeb() {// //方式一:单元测试// driver.get("http://43.139.193.116:8080/login.html");// driver.findElement(By.cssSelector("#username")).clear();// driver.findElement(By.cssSelector("#password")).clear();// driver.findElement(By.cssSelector("#checkpassword")).clear();// //输入账号、密码、验证码// driver.findElement(By.cssSelector("#username")).sendKeys(AppValues.USERNAME);// driver.findElement(By.cssSelector("#password")).sendKeys(AppValues.PASSWORD);// driver.findElement(By.cssSelector("#checkpassword")).sendKeys(AppValues.CODE);// driver.findElement(By.cssSelector("#submit")).click();// driver.findElement(By.cssSelector("body > p.nav > a:nth-child(6)")).click();//整体测试//此时已经有 session 会话了,直接进入即可driver.get("http://43.139.193.116:8080/blog_add.html");}/*** 检验当前页面*/@Test@Order(1)public void webAppear() throws IOException {driver.findElement(By.cssSelector("#title"));driver.findElement(By.cssSelector("#pubdate"));driver.findElement(By.cssSelector("#editorDiv > p.CodeMirror.cm-s-default.CodeMirror-wrap > p.CodeMirror-scroll"));driver.findElement(By.cssSelector("body > p.blog-edit-container > p.title > button:nth-child(4)"));//屏幕截图getScreenShot(getClass().getName());}/*** 测试博客发布功能*/@Test@Order(2)public void postFun() throws InterruptedException, IOException {//输入标题和正文driver.findElement(By.cssSelector("#title")).sendKeys("test");driver.findElement(By.cssSelector("#editorDiv > p.editormd-toolbar > p > ul > li:nth-child(7) > a")).click();//点击发布博客driver.findElement(By.cssSelector("body > p.blog-edit-container > p.title > button:nth-child(4)")).click();Thread.sleep(100);driver.switchTo().alert().accept();Thread.sleep(100);driver.switchTo().alert().dismiss();//检查是否成功发布//屏幕截图getScreenShot(getClass().getName());String e1 = "test";String a1 = driver.findElement(By.cssSelector("#listInfo > p:nth-child(1) > a > p.title")).getText();Assertions.assertEquals(e1, a1);//删除博客driver.findElement(By.xpath("/html/body/p[2]/p[2]/p[2]/p[1]/p/a[3]")).click();Thread.sleep(100);driver.switchTo().alert().accept();//屏幕截图getScreenShot(getClass().getName());Thread.sleep(200);driver.switchTo().alert().accept();}/*** 检验保存草稿功能*/@Test@Order(3)public void saveBlog() throws InterruptedException, IOException {//进入博客发布页面driver.findElement(By.cssSelector("body > p.nav > a:nth-child(6)")).click();//输入标题和正文driver.findElement(By.cssSelector("#title")).sendKeys("test");driver.findElement(By.cssSelector("#editorDiv > p.editormd-toolbar > p > ul > li:nth-child(7) > a")).click();//点击保存草稿driver.findElement(By.cssSelector("body > p.blog-edit-container > p.title > button:nth-child(5)")).click();//处理弹窗Thread.sleep(100);driver.switchTo().alert().accept();//屏幕截图getScreenShot(getClass().getName());//进入草稿页面driver.findElement(By.cssSelector("body > p.nav > a:nth-child(7)")).click();//检验是否保存成功String e1 = "test";String a1 = driver.findElement(By.cssSelector("#listInfo > p:nth-child(1) > a > p.title")).getText();Assertions.assertEquals(e1, a1);//删除草稿driver.findElement(By.xpath("/html/body/p[2]/p[2]/p[1]/p/a[3]")).click();//处理弹窗Thread.sleep(100);driver.switchTo().alert().accept();//屏幕截图getScreenShot(getClass().getName());Thread.sleep(100);driver.switchTo().alert().accept();}}创建一个类名为 OnlineTalkTest 继承 AutoTestUtils ,得到驱动,对在线显示以及聊天功能进行测试,最后进行相应弹窗处理,最后进行屏幕截图.
import com.common.AutoTestUtils;import org.junit.jupiter.api.*;import org.junit.jupiter.params.ParameterizedTest;import org.junit.jupiter.params.provider.CsvSource;import org.junit.jupiter.params.provider.ValueSource;import org.openqa.selenium.Alert;import org.openqa.selenium.By;import org.openqa.selenium.edge.EdgeDriver;import java.io.IOException;@TestMethodOrder(MethodOrderer.OrderAnnotation.class)public class OnlineTalkTest extends AutoTestUtils {private static EdgeDriver driver = AutoTestUtils.getDriver();@BeforeAllpublic static void openWeb() throws InterruptedException {// //方式一:单元测试// driver.get("http://43.139.193.116:8080/login.html");// driver.findElement(By.cssSelector("#username")).clear();// driver.findElement(By.cssSelector("#password")).clear();// driver.findElement(By.cssSelector("#checkpassword")).clear();// //输入账号、密码、验证码// driver.findElement(By.cssSelector("#username")).sendKeys(AppValues.USERNAME);// driver.findElement(By.cssSelector("#password")).sendKeys(AppValues.PASSWORD);// driver.findElement(By.cssSelector("#checkpassword")).sendKeys(AppValues.CODE);// driver.findElement(By.cssSelector("#submit")).click();// Thread.sleep(100);// driver.findElement(By.cssSelector("body > p.nav > a:nth-child(8)")).click();//整体测试//此时已经有 session 会话了,直接进入即可driver.get("http://43.139.193.116:8080/private_letter.html");}/*** 测试页面正常打开*/@Test@Order(1)public void webAppear() throws IOException {driver.findElement(By.cssSelector("body > p.container > p.container-left > p.mycard > img"));driver.findElement(By.cssSelector("body > p.container > p.container-left > p.mycard > span"));driver.findElement(By.cssSelector("body > p.container > p.container-left"));driver.findElement(By.cssSelector("body > p.container > p.container-right > p"));//屏幕截图getScreenShot(getClass().getName());}/*** 测试聊天功能*/@ParameterizedTest@ValueSource(strings = {"你好呀~", "#*&*@%)"})@Order(2)public void TalkTest(String msg) throws InterruptedException, IOException {Thread.sleep(100);//点击头像开始聊天driver.findElement(By.xpath("/html/body/p[2]/p[1]/p[2]/p")).click();//选择输入框开始聊天driver.findElement(By.cssSelector("#messageText")).sendKeys(msg);//提交driver.findElement(By.cssSelector("#sendButton")).click();//处理弹窗Thread.sleep(100);Alert alert = driver.switchTo().alert();String e1 = "对方不在线!";String a1 = alert.getText();Thread.sleep(100);alert.accept();//屏幕截图getScreenShot(getClass().getName());//断言Assertions.assertEquals(e1, a1);}}在所有自动化测试用例执行完后,需要进行退出浏览器,那么我们可以创建一个退出驱动类,放在测试套件类的最后一个测试类。
import com.common.AutoTestUtils;import org.junit.jupiter.api.Test;import org.openqa.selenium.edge.EdgeDriver;/*** 退出驱动类*/public class DriverQuitTest extends AutoTestUtils {private static EdgeDriver driver = AutoTestUtils.getDriver();/*** 退出驱动*/@Testpublic void quitWeb() {driver.quit();}}创建一个类(自定义名为RunSuite),通过 @Suite 注解标识该类为测试套件类(不是测试类),然后使用 @SelectClasses 注解来声明我们要指定的类(通过这个类来运行测试用例),这样优点如下:
1.相比于一个个函数调用来对测试用例进行测试就大大减少了开销和时间;
2.同时指定了类的测试顺序,即在注解@SelectClasses参数中的类测试顺序为从左向右;
import org.junit.platform.suite.api.SelectClasses;import org.junit.platform.suite.api.Suite;@Suite@SelectClasses({LoginTest.class, RegTest.class, fundPasswordTest.class,PersonalHomeTest.class, DraftListTest.class, BlogAndDraftPostTest.class,PersonalInfoTest.class, OnlineTalkTest.class, DriverQuitTest.class})public class RunSuite {}
我们使用以上三个工具针对我们的项目进行性能测试。
a)Virtual User Generator(简称VUG): 用来生成性能测试脚本。
b)Controller: 创建测试场景,运行和监控场景。
c)Analysis: 生成测试报告,分析性能测试结果
a)访问博客登录页;
b)执行登录;
c)进入首页.
1、创建项目
由于我们测试的博客系统是一个Web项目,因此需要创建一个Web性能测试脚本,如下:
2.运行设置
代码编写(我们主要在Action里编写代码~)
主要的操作步骤为:1.打开网页,2.输入账号密码并登录;
在此期间,为了更好的让我们进行性能测试的数据收集,我们可以使用
执行结果和分析:
a)针对我们已经编写好的脚本打开controller工具,创建测试脚本,如下:
b)设置执行策略如下:
这个过程就像是舞台表演一样,如下:
c)场景运行结果
在 controller 创建的场景中直接生成测试报告,如下:
1.虚拟用户运行图:
作用:通过显示的虚拟用户数量可以判断出哪个时间段服务器负载最大(上图00:40 ~ 01:40负载最大)。
2.点击数图(每秒点击率)
作用:通过点击率可以判断出某时间段内服务器的负载。
3.吞吐量图
问题一:为什么吞吐量图和点击数图相似,但是吞吐量图要滞后一点?
问题二:如果请求变多但是吞吐量没变化,原因是什么?
4.事务图
5.平均事务响应时间图
作用: 可以观察到,虚拟用户在性能测试中,每秒在服务器上命中的次数,可以根据命中的次数评估虚拟用户生成的负载量。