2024.5.1【项目测试报告】模拟微信实现网页聊天室

2024-05-03 05:04

本文主要是介绍2024.5.1【项目测试报告】模拟微信实现网页聊天室,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

项目介绍

核心功能

额外拓展

核心技术

 项目页面设计

注册页面

登录页面

找回密码页面

网页聊天室页面

个人中心页面

测试计划

 功能测试

 注册页面

登录页面

找回密码页面

个人中心页面

网页聊天室页面

自动化测试

单例驱动

获取屏幕截图

注册页面自动化测试

登录页面自动化测试

找回密码页面自动化测试

个人中心页面自动化测试

聊天室页面自动化测试

退出驱动

测试套件

自动化测试结果总结

性能测试 

UI 性能测试

录制脚本

运行设置

执行结果与分析

创建测试场景

设置执行策略

场景运行结果


项目介绍

  • 此处实现模拟网页版微信,提供了一个用户之间在线交流平台

核心功能

  • 用户注册、登录、注销、找回密码功能
  • 搜索好友、发送好友申请、添加好友功能
  • 利用 WebSocket 实时查看好友的在线情况
  • 利用 WebSocket 消息推送,选择会话实时聊天
  • 利用 WebSocket 实现会话窗口红色数字提示,实时显示几条消息未读

额外拓展

用户个人中心:支持修改密码、修改昵称
手动实现密码加盐算法,提高用户信息安全性
使用 hutool 工具,实现了登录时图片验证码功能,增加了系统的安全性
增加用户多次登录失败锁定账号功能,并使用 Scheduled 注解实现定时解冻账号
使用 MultipartFile 实现上传头像,使用 WebMvcConfigurer 配置自定义资源映射实现头像展示
使用 HandlerInterceptor 实现统一登录拦截器
使用 ExceptionHandler 注解实现统一异常处理
使用 ResponseBodyAdvice 实现了统一数据格式返回

核心技术

  • Spring Boot / Spring MVC / MyBatis
  • HTML / CSS / JavaScript / Jquery
  • WebSocket
  • MySQL

 项目页面设计

注册页面

  • 客户端输入用户名、密码、密保信息(便于找回密码),通过 ajax 请求发送给后端
  • 后端先检测该用户输入的用户名是否已经被注册,未被注册则针对该密码进行加盐
  • 先利用 UUID 生成一个盐值,随后利用 md5 将(盐值+密码)变为最终的加盐密码
  • 约定存储到数据库的最终密码格式为 (32位盐值+$+32位加盐之后的密码)


登录页面

  • 客户端输入用户名、密码、验证码,通过 ajax 请求发送给后端
  • 后端先检测该用户是否已经注册,再检测该用户是否被锁定、用户输入的验证码是否正确,最后进行密码校验
  • 先从数据库中拿到该用户的最终密码,随后按照之前加密的步骤将该用户输入的明文密码和最终密码中的盐值进行加密,对比新生成的加盐密码与数据库中取出来的加盐密码是否一致
  • 密码一致则登录成功,同时清零该用户密码错误次数,并通过 WebSocket 实时通知其好友,将该用户的状态由离线更改为在线状态
  • 密码不一致则登录失败,该用户密码错误次数 +1,密码错误次数累计到 5 次则直接锁定该用户账号


找回密码页面

  • 客户端输入找回账号、真实姓名、身份证号、密码、确认密码,通过 ajax 请求发送给后端
  • 后端先判断该用户名是否存在,再判断密保信息是否对应正确,最后判断新密码与确认密码是否相同
  • 如果相同则针对新密码进行加盐处理,并更新数据库中该用户对应的最终密码


网页聊天室页面

  • 会话页面

  • 当同意他人的好友申请时,将自动创建会话,并向新添加的好友发送初始消息
  • 当你选择某一会话时,当前会话接收到的消息不会有未读消息红色数字提示
  • 仅有未选择的会话,在收到消息时才会出现未读消息红色数字提示
  • 当你点击该会话,未读消息红色数字提示自动清零消失
  • 最后可通过右侧的聊天框针对选定的会话进行实时聊天

  • 好友页面

  • 展示所有已添加的好友及其状态
  • 当某一好友上线时,将通过 WebSocket 实时通知到当前用户,并实时将该好友的状态改为在线
  • 当某一好友下线时,同样通过 WebSocket 实时通知到当前用户,并实时将该好友的状态改为离线

  • 查询好友页面
  • 用户在输入框中输入关键字进行好友搜索
  • 该搜索为模糊查询,搜索结果将展示所有包含该搜索字符的账号
  • 随后找到想添加的好友,并在其输入框中输入申请理由,最后点击发送申请,那位好友即可收到当前用户发送的好友申请
  • 当然此处不能重复发送申请,如果那位好友拒绝了你,则可以重复发送好友申请

  • 添加好友页面
  • 展示所有当前用户收到的好友申请
  • 当前用户点击拒绝,则将删除该项好友申请
  • 当前用户点击同意,则会自动创建与该好友的会话,并发送初始消息


个人中心页面

  • 当前用户点击上传头像,即可弹出文件资源管理器,便可选择头像上传,前端进行文件格式验证,最后实时更新头像
  • 当前用户在昵称栏中输入想要修改的账号名,点击更改即可实时更新账号名
  • 当前用户输入旧密码,再输入新密码和确认密码,旧密码验证通过即可实时更新账号密码

测试计划

 功能测试

  • 编写测试用例


 注册页面

  • 输入异常的账号、密码、确认密码、真实姓名、身份证号

预期结果

  • 对应的弹窗提示

实际结果

  • 输入正常的账号、密码、确认密码、真实姓名、身份证号

预期结果

  • 弹窗提示是否跳转至登录页面

实际结果


登录页面

  • 输入异常的账号、密码、验证码

预期结果

  • 弹窗对应提示

实际结果

  • 输入正常的账号和密码

预期结果

  • 跳转到聊天室页面

实际结果


找回密码页面

  • 异常填写找回账号名、密保信息、密码、确认密码

预期结果

  • 对应的弹窗提示

实际结果

  • 正常填写找回账号名、密保信息、密码、确认密码

预期结果

  • 弹窗提示密码找回成功,是否跳转到登录页

实际结果


个人中心页面

  • 异常修改头像 —— 上传文件大小大于 5MB 的文件

预期结果

  • 对应弹窗提示

实际结果

  • 异常修改头像 —— 上传非 jpg 和 png 格式的文件

预期结果

  • 对应弹窗提示

实际结果

  • 正常修改头像 —— 上传文件大小大于 5MB 的文件

预期结果

  • 上传成功后,头像实时更新

实际结果


网页聊天室页面

  • 正常查询新的朋友 —— 无匹配到的账号

预期结果

  • 显示查找用户不存在

实际结果

  • 正常查询新的朋友 —— 有一个或多个匹配到的账号

预期结果

  • 自己本身 和 已添加的好友无法被搜索到 并展示在搜索结果页面中
  • 匹配到的用户成列来展示

实际结果

  • 发送好友申请

预期结果

  • 对方能接收到该条好友申请

实际结果

  • 重复发送好友申请 —— 未被对方处理该申请前

预期结果

  • 对应弹窗提示

实际结果

  • 同意好友申请

预期结果

  • 删除该项好友申请
  • 好友列表实时更新并显示新添加的好友
  • 会话列表自动创建会话并向新添加的好友发送初始消息

实际结果

自动化测试

单例驱动

  • 自动化测试程序过程中, 会很频繁的使用驱动
  • 如果频繁的创建和销毁驱动,其开销还是比较大的,因此我们可以使用懒汉模式来加载驱动
  • 这样既能保证驱动不会频繁创建(程序运行过程中保持单例),又能减轻程序刚开始启动时的系统开销(只有用到驱动时才去加载它)
  • 当然如果其他类需要用到驱动的话,直接继承该类即可

获取屏幕截图

  • 当我们测试用例出错时,我们需要查看当时网页出现的情况,那么就需要使用屏幕截图来排查问题
  • 我们可以使用 getScreenshotAs 方法来保存屏幕截图,在每个测试用例执行完后进行一次屏幕截图
  • 屏幕截图统一保存到一个路径下,文件名以当时时间进行组织(防止保存屏幕截图出现覆盖情况)
  • 综上我们便可以在 AutoTestUtils 类下加上保存截图的方法,方便其他类调用
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
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.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;public class AutoTestUtils {private static ChromeDriver driver;public static ChromeDriver getDriver() {ChromeOptions options = new ChromeOptions();options.addArguments("--remote-allow-origins=*");if(driver == null) {driver = new ChromeDriver(options);// 创建隐式等待,设置最长等待时间为 10sdriver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);}return driver;}/** 获取屏幕截图,将用例执行结果保存下来* */public void getScreenShot(String str) throws IOException {List<String> list = getTime();String fileName = "./src/test/java/com/blogWebAutoTest/" + list.get(0) + "/" + str + "_" + list.get(1) + ".png";File srcFile = driver.getScreenshotAs(OutputType.FILE);
//        把生成的截图放入指定路径FileUtils.copyFile(srcFile,new File(fileName));}//    获取当前时间(记录每个屏幕截图是什么时候拍摄的)private List<String> getTime() {SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyMMdd-HHmmssSS");SimpleDateFormat sdf2 = new SimpleDateFormat("yyyyMMdd");
//        保存的文件夹名 当天的年月日 + 具体时间String fileName = sdf1.format(System.currentTimeMillis());
//        保存的图片名  当天的年月日String dirName = sdf2.format(System.currentTimeMillis());List<String> list = new ArrayList<>();list.add(dirName);list.add(fileName);return list;}
}

注册页面自动化测试

  • 此处我们创建一个 RegTest 类继承 AutoTestUtils 类得到驱动
  • 先测试注册页面是否正常打开,再找几个典型的用例使用参数化注解进行测试注册功能
  • 最后进行相应弹窗处理,进行屏幕截图
package UserTest;import 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 java.io.IOException;@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class RegTest extends AutoTestUtils {//    获取到驱动private static WebDriver driver = AutoTestUtils.getDriver();/** 打开网页* 注册页面一般是从登录页面进入* */@BeforeAllpublic static void openWeb() {
//      先打开登录页面driver.get("http://116.196.82.203:8080/login.html");
//      再点击登录页面中的 注册链接按钮driver.findElement(By.cssSelector("body > div.login-container > div > div > div.row2 > a:nth-child(3)")).click();driver.manage().window().maximize();}/** 验证网页正常打开* */@Test@Order(1)public void elementsAppear() throws IOException {
//        用户名输入框driver.findElement(By.cssSelector("#username"));
//        密码输入框driver.findElement(By.cssSelector("#password"));
//        确认密码输入框driver.findElement(By.cssSelector("#confirm_password"));
//        真实姓名输入框driver.findElement(By.cssSelector("#realname"));
//        身份证号输入框driver.findElement(By.cssSelector("#idcard"));
//        提交按钮driver.findElement(By.cssSelector("#submit"));getScreenShot(getClass().getName());}/** 异常测试注册功能* 参数一: 尝试注册已注册用户* 参数二: 密码与确认密码不一致* 参数三: 身份证号格式有误* */@ParameterizedTest@CsvSource({"mastermao,123,123,王小林,430202123405080222","testMan,123,1234,王小林,430202123405080222","zhansan,123,123,王小林,4302021234"})@Order(2)public void regFunTest(String username,String password,String confirmPassword,String realName,String idCard) throws InterruptedException, IOException {
//        拿到元素WebElement inputUserName = driver.findElement(By.cssSelector("#username"));WebElement inputPassword = driver.findElement(By.cssSelector("#password"));WebElement inputConfirmPassword = driver.findElement(By.cssSelector("#confirm_password"));WebElement inputRealName = driver.findElement(By.cssSelector("#realname"));WebElement inputIdCard = driver.findElement(By.cssSelector("#idcard"));WebElement button = driver.findElement(By.cssSelector("#submit"));
//        再清除输入框inputUserName.clear();inputPassword.clear();inputConfirmPassword.clear();inputRealName.clear();inputIdCard.clear();
//        输入用例inputUserName.sendKeys(username);inputPassword.sendKeys(password);inputConfirmPassword.sendKeys(confirmPassword);inputRealName.sendKeys(realName);inputIdCard.sendKeys(idCard);
//        提交button.click();
//        强制等待弹窗Thread.sleep(100);Alert alert = driver.switchTo().alert();
//        期望结果String expect = "注册名已注册/密码与确认密码不一致/身份证号格式有误";String actual = "注册名已注册/密码与确认密码不一致/身份证号格式有误";if(alert != null) {alert.accept();}else {actual = "当前用例执行失败";}Assertions.assertEquals(expect,actual);
//        屏幕截图getScreenShot(getClass().getName());}
}

登录页面自动化测试

  • 此处我们创建一个 LoginTest 类继承 AutoTestUtils 类得到驱动
  • 先测试登录页面是否正常打开,再找几个典型的用例对异常、正常登录分别进行测试
  • 最后进行相应弹窗处理,进行屏幕截图
package UserTest;import 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.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;import java.io.IOException;@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class LoginTest extends AutoTestUtils {//  获取到驱动private static ChromeDriver driver = AutoTestUtils.getDriver();/** 打开网页* @Before 标识在所有测试用例执行之前执行依次* */@BeforeAllpublic static void openWeb() {driver.get("http://116.196.82.203:8080/login.html");driver.manage().window().maximize();}/** 检测登录页面是否能正常打开* */@Test@Order(1)public void elementsAppear() throws IOException {
//        用户名输入框driver.findElement(By.cssSelector("#username"));
//        密码输入框driver.findElement(By.cssSelector("#password"));
//        验证码输入框driver.findElement(By.cssSelector("#captcha"));
//        找回密码链接driver.findElement(By.cssSelector("body > div.login-container > div > div > div.row2 > a:nth-child(1)"));
//        注册账号链接driver.findElement(By.cssSelector("body > div.login-container > div > div > div.row2 > a:nth-child(3)"));
//        登录按钮driver.findElement(By.cssSelector("#submit"));
//        屏幕截图getScreenShot(getClass().getName());}/** 异常测试注册功能* 参数一: 尝试登录未注册用户* 参数二: 密码输入错误 登录账号* 参数三: 验证码输入错误 登陆账号* 0000 为万能验证码*/@ParameterizedTest@CsvSource({"adm*,123,0000","mastermao,123456,0000","mastermao,123,warn"})@Order(2)public void loginAbnormalTest (String username,String password, String captcha) throws IOException, InterruptedException {
//        拿到元素WebElement inputUserName = driver.findElement(By.cssSelector("#username"));WebElement inputPassword = driver.findElement(By.cssSelector("#password"));WebElement inputCaptcha = driver.findElement(By.cssSelector("#captcha"));WebElement button = driver.findElement(By.cssSelector("#submit"));
//      清除用户名、密码框、验证码inputUserName.clear();inputPassword.clear();inputCaptcha.clear();
//        输入账号、密码、验证码inputUserName.sendKeys(username);inputPassword.sendKeys(password);inputCaptcha.sendKeys(captcha);
//        点击登录button.click();
//        强制等待弹窗Thread.sleep(100);Alert alert = driver.switchTo().alert();
//        期望结果String expect = "用户名/密码/验证码错误";String actual = "用户名/密码/验证码错误";if(alert != null && !alert.getText().equals("该用户未注册!是否要跳转到登录页面?")) {alert.accept();}else if(alert != null && alert.getText().equals("该用户未注册!是否要跳转到登录页面?")){alert.dismiss();}else {actual = "当前用例执行失败";}Assertions.assertEquals(expect,actual);
//        屏幕截图getScreenShot(getClass().getName());}/** 正常登录测试* */@ParameterizedTest@CsvSource("mastermao,123,0000")@Order(3)public void loginNormalTest(String username,String password,String captcha) throws InterruptedException, IOException {
//        拿到元素WebElement inputUserName = driver.findElement(By.cssSelector("#username"));WebElement inputPassword = driver.findElement(By.cssSelector("#password"));WebElement inputCaptcha = driver.findElement(By.cssSelector("#captcha"));WebElement button = driver.findElement(By.cssSelector("#submit"));
//        清除用户名、密码框、验证码inputUserName.clear();inputPassword.clear();inputCaptcha.clear();
//        输入账号、密码、验证码inputUserName.sendKeys(username);inputPassword.sendKeys(password);inputCaptcha.sendKeys(captcha);
//        点击登录button.click();
//        强制等待 加载页面Thread.sleep(100);
//        屏幕截图getScreenShot(getClass().getName());
//        登陆成功后需返回登录界面
//        点击注销driver.findElement(By.cssSelector("body > div.nav > a:nth-child(4)")).click();
//        强制等待弹窗Thread.sleep(100);
//        处理弹窗driver.switchTo().alert().accept();
//        等待处理完成Thread.sleep(100);
//        屏幕截图getScreenShot(getClass().getName());}
}

找回密码页面自动化测试

  • 此处我们创建一个 FundPasswordTest 类继承 AutoTestUtils 类得到驱动
  • 先测试找回密码页面是否正常打开,再找几个典型的用例使用参数化注解对其进行测试
  • 最后进行相应弹窗处理,进行屏幕截图
package UserTest;import 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.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;import java.io.IOException;@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class FundPasswordTest extends AutoTestUtils {//    获取驱动private static ChromeDriver driver = AutoTestUtils.getDriver();/** 打开页面* 找回密码页面一般是从登录页面进入* */@BeforeAllpublic static void openWeb() {
//      先打开登录页面driver.get("http://116.196.82.203:8080/login.html");
//      再点击登录页面中的 找回密码链接按钮driver.findElement(By.cssSelector("body > div.login-container > div > div > div.row2 > a:nth-child(1)")).click();driver.manage().window().maximize();}/** 验证页面正常打开* */@Test@Order(1)public void elementsAppear() throws IOException {
//        找回账号名输入框driver.findElement(By.cssSelector("#username"));
//        真实姓名输入框driver.findElement(By.cssSelector("#realname"));
//        身份证号输入框driver.findElement(By.cssSelector("#idcard"));
//        新密码输入框driver.findElement(By.cssSelector("#password"));
//        确认密码输入框driver.findElement(By.cssSelector("#confirm_password"));
//        提交按钮driver.findElement(By.cssSelector("#submit"));
//        屏幕截图getScreenShot(getClass().getName());}/** 异常找回密码测试* 参数一: 验证找回不存在账号* 参数二: 验证密保信息输入错误* 参数三: 身份证号正确性校验* 参数四: 新密码与确认密码不一致* */@ParameterizedTest@CsvSource({"adm*,王小林,432204422225080732,123,123","xiaowang,王小林,432204422225080739,123,123","xiaowang,王小林,43220,123,123","xiaowang,王小林,432204422225080732,123,1234"})@Order(2)public void fundPasswordFunExceptionTest(String userName,String realName,String IdCard,String newPassword,String confirmPassword) throws InterruptedException, IOException {
//      拿到元素WebElement inputUserName = driver.findElement(By.cssSelector("#username"));WebElement inputRealName = driver.findElement(By.cssSelector("#realname"));WebElement inputIdCard = driver.findElement(By.cssSelector("#idcard"));WebElement inputNewPassword = driver.findElement(By.cssSelector("#password"));WebElement inputConfirmPassword = driver.findElement(By.cssSelector("#confirm_password"));WebElement button = driver.findElement(By.cssSelector("#submit"));
//      清除找回账号、真实姓名、身份证号、新密码、确认密码inputUserName.clear();inputRealName.clear();inputIdCard.clear();inputNewPassword.clear();inputConfirmPassword.clear();
//      输入找回账号、真实姓名、身份证号、新密码、确认密码inputUserName.sendKeys(userName);inputRealName.sendKeys(realName);inputIdCard.sendKeys(IdCard);inputNewPassword.sendKeys(newPassword);inputConfirmPassword.sendKeys(confirmPassword);
//        点击提交button.click();
//        强制等待弹窗Thread.sleep(100);Alert alert = driver.switchTo().alert();
//        期望结果String expect = "找回账号不存在/密保信息错误/身份证号格式有误/密码与确认密码不一致";String actual = "找回账号不存在/密保信息错误/身份证号格式有误/密码与确认密码不一致";if(alert != null) {alert.accept();}else {actual = "当前用例执行失败";}Assertions.assertEquals(expect,actual);
//        屏幕截图getScreenShot(getClass().getName());}/** 正常找回密码测试* */@ParameterizedTest@CsvSource("xiaowang,王小林,432204422225080732,123,123")@Order(3)public void fundPasswordFuNormalTest(String userName,String realName,String IdCard,String newPassword,String confirmPassword) throws InterruptedException, IOException {
//      拿到元素WebElement inputUserName = driver.findElement(By.cssSelector("#username"));WebElement inputRealName = driver.findElement(By.cssSelector("#realname"));WebElement inputIdCard = driver.findElement(By.cssSelector("#idcard"));WebElement inputNewPassword = driver.findElement(By.cssSelector("#password"));WebElement inputConfirmPassword = driver.findElement(By.cssSelector("#confirm_password"));WebElement button = driver.findElement(By.cssSelector("#submit"));
//      清除找回账号、真实姓名、身份证号、新密码、确认密码inputUserName.clear();inputRealName.clear();inputIdCard.clear();inputNewPassword.clear();inputConfirmPassword.clear();
//      输入找回账号、真实姓名、身份证号、新密码、确认密码inputUserName.sendKeys(userName);inputRealName.sendKeys(realName);inputIdCard.sendKeys(IdCard);inputNewPassword.sendKeys(newPassword);inputConfirmPassword.sendKeys(confirmPassword);
//      点击提交button.click();
//      处理弹窗Thread.sleep(100);driver.switchTo().alert().accept();
//      屏幕截图getScreenShot(getClass().getName());}
}

个人中心页面自动化测试

  • 此处我们创建一个 PersonalCenterTest 类继承 AutoTestUtils 类得到驱动
  • 先测试找回密码页面是否正常打开,对修改账号名、修改密码使用典型用例进行测试
  • 最后进行相应弹窗处理,进行屏幕截图
package UserTest;import 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.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;import java.io.IOException;@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class PersonalCenterTest extends AutoTestUtils {private static ChromeDriver driver = AutoTestUtils.getDriver();@BeforeAllpublic static void openWeb() throws InterruptedException {
//        1) 单元测试 先登录,再进入个人中心页面
//        拿到元素driver.get("http://116.196.82.203:8080/login.html");driver.manage().window().maximize();WebElement inputUserName = driver.findElement(By.cssSelector("#username"));WebElement inputPassword = driver.findElement(By.cssSelector("#password"));WebElement inputCaptcha = driver.findElement(By.cssSelector("#captcha"));WebElement button = driver.findElement(By.cssSelector("#submit"));
//        清除用户名、密码框、验证码inputUserName.clear();inputPassword.clear();inputCaptcha.clear();
//        输入账号、密码、验证码inputUserName.sendKeys("mastermao");inputPassword.sendKeys("123");inputCaptcha.sendKeys("0000");
//        点击登录button.click();
//        强制等待页面加载Thread.sleep(100);driver.findElement(By.cssSelector("body > div.nav > a:nth-child(3)")).click();//        2) 整体测试 此时已经存在 session 会话,直接进入即可
//        driver.get("http://116.196.82.203:8080/personal_center.html");}/** 验证页面正常打开* */@Test@Order(1)public void elementsAppear() throws IOException {
//        账号名展示driver.findElement(By.cssSelector("#username"));
//        头像展示driver.findElement(By.cssSelector("#avatarImg"));
//        上传头像按钮driver.findElement(By.cssSelector("#changeBtn"));
//        更换昵称输入框driver.findElement(By.cssSelector("#newname"));
//        更改昵称按钮driver.findElement(By.cssSelector("#smallsubmit"));
//        修改密码 —— 旧密码输入框driver.findElement(By.cssSelector("#password2"));
//        修改密码 —— 新密码输入框driver.findElement(By.cssSelector("#password3"));
//        修改密码 —— 确认密码输入框driver.findElement(By.cssSelector("#password4"));
//        修改密码 —— 提交按钮driver.findElement(By.cssSelector("#submit"));
//        屏幕截图getScreenShot(getClass().getName());}/** 异常修改账号名(昵称)测试* 参数一: 尝试修改成已存在的账号名* */@ParameterizedTest@ValueSource(strings = {"123","xiaowang"})@Order(2)public void basicInfoAbnormalTest(String newName) throws InterruptedException, IOException {
//        清除输入框WebElement inputNewName  = driver.findElement(By.cssSelector("#newname"));inputNewName.clear();
//        填入想要更换的账号名inputNewName.sendKeys(newName);
//        点击更改按钮driver.findElement(By.cssSelector("#smallsubmit")).click();
//        处理弹窗Thread.sleep(100);
//        预期结果String text = "新用户名已经被注册,请重新填写!";
//        实际结果String alertText = driver.switchTo().alert().getText();
//        断言Assertions.assertEquals(text,alertText);driver.switchTo().alert().accept();
//        屏幕截图getScreenShot(getClass().getName());}/** 正常修改账号名(昵称)测试* 此处修改账号名我需要形成闭环,账号名被修改影响之后的测试* */@ParameterizedTest@ValueSource(strings = {"1234","xiaozhang","&*^%$","小张","mastermao"})@Order(3)public void basicInfoTest(String newName) throws InterruptedException, IOException {
//        清除输入框WebElement inputNewName  = driver.findElement(By.cssSelector("#newname"));inputNewName.clear();
//        填入想要更换的账号名inputNewName.sendKeys(newName);
//        点击更改按钮driver.findElement(By.cssSelector("#smallsubmit")).click();
//        处理弹窗Thread.sleep(100);driver.switchTo().alert().accept();
//        屏幕截图getScreenShot(getClass().getName());}/** 异常修改密码测试* 参数一: 旧密码输入错误(1)* 参数二: 旧密码输入错误(2)* 参数三: 新密码与确认密码不一致(1)* 参数四: 新密码与确认密码不一致(2)**/@ParameterizedTest@CsvSource({"12345678,123456,123456","*#&2*,123456,123456","123,adfa,1551sf8","123,489,123"})@Order(4)public void updatePasswordAbnormalTest(String oldPassword,String newPassword,String confirmPassword) throws InterruptedException, IOException {
//        修改密码 —— 旧密码输入框WebElement inputOldPassword = driver.findElement(By.cssSelector("#password2"));
//        修改密码 —— 新密码输入框WebElement inputNewPassword = driver.findElement(By.cssSelector("#password3"));
//        修改密码 —— 确认密码输入框WebElement inputConfirmPassword = driver.findElement(By.cssSelector("#password4"));
//        修改密码 —— 提交按钮WebElement button = driver.findElement(By.cssSelector("#submit"));
//        清除输入框inputOldPassword.clear();inputNewPassword.clear();inputConfirmPassword.clear();
//        输入参数inputOldPassword.sendKeys(oldPassword);inputNewPassword.sendKeys(newPassword);inputConfirmPassword.sendKeys(confirmPassword);
//        点击提交button.click();
//        处理弹窗Thread.sleep(100);Alert alert = driver.switchTo().alert();
//        期望结果String expect = "旧密码错误/密码与确认密码不一致";String actual = "旧密码错误/密码与确认密码不一致";if(alert != null) {alert.accept();}else {actual = "当前用例执行失败";}Assertions.assertEquals(expect,actual);
//        屏幕截图getScreenShot(getClass().getName());}/** 正常修改密码测试* */@ParameterizedTest@CsvSource({"123,123456,123456", "123456,123,123"})@Order(5)public void updatePasswordTest(String oldPassword,String newPassword,String confirmPassword) throws InterruptedException, IOException {
//        修改密码 —— 旧密码输入框WebElement inputOldPassword = driver.findElement(By.cssSelector("#password2"));
//        修改密码 —— 新密码输入框WebElement inputNewPassword = driver.findElement(By.cssSelector("#password3"));
//        修改密码 —— 确认密码输入框WebElement inputConfirmPassword = driver.findElement(By.cssSelector("#password4"));
//        修改密码 —— 提交按钮WebElement button = driver.findElement(By.cssSelector("#submit"));
//        清除输入框inputOldPassword.clear();inputNewPassword.clear();inputConfirmPassword.clear();
//        输入参数inputOldPassword.sendKeys(oldPassword);inputNewPassword.sendKeys(newPassword);inputConfirmPassword.sendKeys(confirmPassword);
//        点击提交button.click();
//        处理弹窗Thread.sleep(100);
//        预期结果String text = "恭喜!修改密码成功!";
//        实际结果String alertText = driver.switchTo().alert().getText();
//        断言Assertions.assertEquals(text,alertText);driver.switchTo().alert().accept();
//        屏幕截图getScreenShot(getClass().getName());}
}

聊天室页面自动化测试

  • 此处我们创建一个 ClientTest 类继承 AutoTestUtils 类得到驱动
  • 先对在线显示以及聊天功能进行测试,最后进行相应的弹窗处理,最后进行屏幕截图
package UserTest;import common.AutoTestUtils;
import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;import java.io.IOException;@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class ClientTest extends AutoTestUtils {//    获取驱动public static ChromeDriver driver = AutoTestUtils.getDriver();@BeforeAllpublic static void openWeb() throws InterruptedException {1) 单元测试 先登录,再进入个人中心页面拿到元素
//        driver.get("http://116.196.82.203:8080/login.html");
//        driver.manage().window().maximize();
//        WebElement inputUserName = driver.findElement(By.cssSelector("#username"));
//        WebElement inputPassword = driver.findElement(By.cssSelector("#password"));
//        WebElement inputCaptcha = driver.findElement(By.cssSelector("#captcha"));
//        WebElement button = driver.findElement(By.cssSelector("#submit"));清除用户名、密码框、验证码
//        inputUserName.clear();
//        inputPassword.clear();
//        inputCaptcha.clear();输入账号、密码、验证码
//        inputUserName.sendKeys("mastermao");
//        inputPassword.sendKeys("123");
//        inputCaptcha.sendKeys("0000");点击登录
//        button.click();
//        2)  整体测试 此时已经存在 session 会话,直接进入即可driver.get("http://116.196.82.203:8080/client.html");}/** 测试页面正常打开* */@Test@Order(1)public void elementsAppear() throws IOException {
//        主页个人头像driver.findElement(By.cssSelector("#avatarImg"));
//        主页个人账号名driver.findElement(By.cssSelector("#username"));
//        搜索输入框driver.findElement(By.cssSelector("body > div.client-container > div > div.left > div.search > input[type=text]"));
//        搜索按钮driver.findElement(By.cssSelector("body > div.client-container > div > div.left > div.search > button"));
//        会话标签图driver.findElement(By.cssSelector("body > div.client-container > div > div.left > div.tab > div.tab-session"));
//        好友标签图driver.findElement(By.cssSelector("body > div.client-container > div > div.left > div.tab > div.tab-friend"));
//        添加好友标签图driver.findElement(By.cssSelector("body > div.client-container > div > div.left > div.tab > div.tab-add-friend"));
//        聊天输入框driver.findElement(By.cssSelector("#message-list > textarea"));
//        发送按钮driver.findElement(By.cssSelector("#message-list > div.ctrl > button"));
//        屏幕截图getScreenShot(getClass().getName());}/** 测试聊天功能* */@ParameterizedTest@ValueSource(strings = {"我在测试中很高兴认识你!","我在测试中啦啦啦!","一二三四五六七八九十"})@Order(2)public void TalkTest(String msg) throws InterruptedException, IOException {
//        点击头像开始聊天driver.findElement(By.xpath("//*[@id=\"session-list\"]/li[1]")).click();
//        选择输入框开始聊天driver.findElement(By.cssSelector("#message-list > textarea")).sendKeys(msg);
//        点击发送driver.findElement(By.cssSelector("#message-list > div.ctrl > button")).click();Thread.sleep(100);
//        屏幕截图getScreenShot(getClass().getName());}
}

退出驱动

  • 所有自动化测试用例执行完后,需要退出浏览器
  • 此处我们创建一个退出驱动类,放到测试套件类的最后一个测试类
package common;import org.junit.jupiter.api.Test;
import org.openqa.selenium.chrome.ChromeDriver;public class DriverQuitTest extends AutoTestUtils{private static ChromeDriver driver  = AutoTestUtils.getDriver();/** 退出驱动* */@Testpublic void quitWeb() {driver.quit();}
}

测试套件

  • 此处我们创建一个 RunSuite 类,通过 @Suite 注解标识该类为测试套件类
  • 然后使用 @SelectClasses 注解来声明我们要指定的类
  • 最后通过 RunSuite 类来运行测试用例

优点:

  • 相比于使用函数调用来对测试用例进行测试,当前方式大大减少了开销和时间
  • 可以直接指定类的测试顺序,即在注解 @SelectClasses 参数中的测试顺序为从左向右
package common;import UserTest.*;
import org.junit.platform.suite.api.SelectClasses;
import org.junit.platform.suite.api.Suite;@Suite
@SelectClasses({RegTest.class, FundPasswordTest.class, LoginTest.class, PersonalCenterTest.class, ClientTest.class})
public class RunSuite {
}

自动化测试结果总结

​​​​​​​

  • 使用 Junit5 中提供的注解,避免生成过多对象从而造成资源和时间上的浪费,提高自动化执行的效率
  • 使用单例模式创建驱动,避免每个用例重复创建驱动造成时间和资源的浪费
  • 使用隐藏式等待,提高了自动化运行效率,提高了自动化的稳定性
  • 使用参数化,保持用例的整洁,提高代码的可读性
  • 使用屏幕截图,方便问题的追溯以及解决

性能测试 

  • 此处我将使用 Load Runner 三件套对该项目进行性能测试

UI 性能测试

  • 访问登录页面 ——> 执行登录操作 ——> 进入聊天室页面
录制脚本
  • 此处为了进行性能测试的数据收集,我自主添加了事务、集合点、检查点、参数化
  • 事务:衡量性能的重要指标,通过观察每秒事务通过数来衡量性能
  • 集合点:让所有的虚拟用户执行到集合点时断在集合,满足条件后一起执行下一个步骤
  • 检查点:可以用来检测当前页面的元素是否存在以及存在个数
  • 参数化:通过提供的数据源可以实现多个参数逐个执行
Action()
{web_add_cookie("JSESSIONID=8EA4077CAC83B39B832BF2F68CA04C27; DOMAIN=116.196.82.203");//	开启事务1lr_start_transaction("index_trans");//	登录页面的检查点web_reg_find("Fail=NotFound","Search=All","SaveCount=","Text=login",LAST);//	1、访问登录页面web_url("login.html", "URL=http://116.196.82.203:8080/login.html", "Resource=0", "RecContentType=text/html", "Referer=http://116.196.82.203:8080/login.html", "Snapshot=t1.inf", "Mode=HTML", EXTRARES, "Url=/user/captcha?1714547166056", ENDITEM, LAST);//	登录的集合点lr_rendezvous("login_rendezvous");//	开启事务2lr_start_transaction("login_trans");//	输入登录账号和密码web_submit_data("login", "Action=http://116.196.82.203:8080/user/login", "Method=POST", "RecContentType=application/json", "Referer=http://116.196.82.203:8080/login.html", "Snapshot=t2.inf", "Mode=HTML", ITEMDATA, "Name=username", "Value={username}", ENDITEM, "Name=password", "Value=123", ENDITEM, "Name=captcha", "Value=0000", ENDITEM, EXTRARES, "Url=userinfo", "Referer=http://116.196.82.203:8080/client.html", ENDITEM, "Url=../session/session-list", "Referer=http://116.196.82.203:8080/client.html", ENDITEM, "Url=../friend/friend-list", "Referer=http://116.196.82.203:8080/client.html", ENDITEM, "Url=../friend/get-friend-request", "Referer=http://116.196.82.203:8080/client.html", ENDITEM, LAST);//	结束事务2lr_end_transaction("login_trans", LR_AUTO);//	结束事务1lr_end_transaction("index_trans", LR_AUTO);return 0;
}
运行设置
  • 此处我针对 username 进行了参数化,这些用户名对应的密码均为 "123"

  • 因为我参数化设置了三个账号名,所以此处将 Action 脚本执行次数修改为 3

  • 与此同时,我还想让参数值能够直接打印到日志信息中

执行结果与分析

创建测试场景
  • 此处我针对上述脚本创建测试场景,设置 3 个虚拟用户

设置执行策略
  • 此处我们分别设置 虚拟用户初始化、启动、运行时间、退出,这四个方面的执行策略

场景运行结果
  • 此处我直接查看 Analysis 所生成的测试报告
  • 关于事务总结模块,一般不太注重最大值和最小值,除非差距太大,就需考虑其稳定性
  • 主要关注 平均值 和 标准偏差,标准偏差值越大,则越不稳定

  • 虚拟用户运行图表展示
  • 作用 ——> 通过显示的虚拟用户数来判断出哪个时间段服务器负载最大

  • 每秒点击数图表展示
  • 作用 ——> 通过点击率可以判断出某时间段内服务器的负载

  • 吞吐量图表展示
  • 注意对比吞吐量与每秒点击数图标
  • 虽然二者图表相似,但仔细观察吞吐量均基本滞后于每秒点击数
  • 这也主要因为吞吐量表示的是响应返回的资源数量,肯定是先有请求再有返回

  • 事务图表展示

  • 平均事务响应时间图表展示
  • 作用 ——> 可以观察到虚拟用户在性能测试中,每秒在服务器上的命中次数,可以根据命中次数评估虚拟用户生成的负载量

这篇关于2024.5.1【项目测试报告】模拟微信实现网页聊天室的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/955884

相关文章

C++对象布局及多态实现探索之内存布局(整理的很多链接)

本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等 文章链接:http://dev.yesky.com/254/2191254.shtml      论C/C++函数间动态内存的传递 (2005-07-30)   当你涉及到C/C++的核心编程的时候,你会无止境地与内存管理打交道。 文章链接:http://dev.yesky

问题:第一次世界大战的起止时间是 #其他#学习方法#微信

问题:第一次世界大战的起止时间是 A.1913 ~1918 年 B.1913 ~1918 年 C.1914 ~1918 年 D.1914 ~1919 年 参考答案如图所示

[职场] 护理专业简历怎么写 #经验分享#微信

护理专业简历怎么写   很多想成为一名护理方面的从业者,但是又不知道应该怎么制作一份简历,现在这里分享了一份护理方面的简历模板供大家参考。   蓝山山   年龄:24   号码:12345678910   地址:上海市 邮箱:jianli@jianli.com   教育背景   时间:2011-09到2015-06   学校:蓝山大学   专业:护理学   学历:本科

大学湖北中医药大学法医学试题及答案,分享几个实用搜题和学习工具 #微信#学习方法#职场发展

今天分享拥有拍照搜题、文字搜题、语音搜题、多重搜题等搜题模式,可以快速查找问题解析,加深对题目答案的理解。 1.快练题 这是一个网站 找题的网站海量题库,在线搜题,快速刷题~为您提供百万优质题库,直接搜索题库名称,支持多种刷题模式:顺序练习、语音听题、本地搜题、顺序阅读、模拟考试、组卷考试、赶快下载吧! 2.彩虹搜题 这是个老公众号了 支持手写输入,截图搜题,详细步骤,解题必备

uniapp接入微信小程序原生代码配置方案(优化版)

uniapp项目需要把微信小程序原生语法的功能代码嵌套过来,无需把原生代码转换为uniapp,可以配置拷贝的方式集成过来 1、拷贝代码包到src目录 2、vue.config.js中配置原生代码包直接拷贝到编译目录中 3、pages.json中配置分包目录,原生入口组件的路径 4、manifest.json中配置分包,使用原生组件 5、需要把原生代码包里的页面修改成组件的方

用Microsoft.Extensions.Hosting 管理WPF项目.

首先引入必要的包: <ItemGroup><PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" /><PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" /><PackageReference Include="Serilog

eclipse运行springboot项目,找不到主类

解决办法尝试了很多种,下载sts压缩包行不通。最后解决办法如图: help--->Eclipse Marketplace--->Popular--->找到Spring Tools 3---->Installed。

通过SSH隧道实现通过远程服务器上外网

搭建隧道 autossh -M 0 -f -D 1080 -C -N user1@remotehost##验证隧道是否生效,查看1080端口是否启动netstat -tuln | grep 1080## 测试ssh 隧道是否生效curl -x socks5h://127.0.0.1:1080 -I http://www.github.com 将autossh 设置为服务,隧道开机启动

问题-windows-VPN不正确关闭导致网页打不开

为什么会发生这类事情呢? 主要原因是关机之前vpn没有关掉导致的。 至于为什么没关掉vpn会导致网页打不开,我猜测是因为vpn建立的链接没被更改。 正确关掉vpn的时候,会把ip链接断掉,如果你不正确关掉,ip链接没有断掉,此时你vpn又是没启动的,没有域名解析,所以就打不开网站。 你可以在打不开网页的时候,把vpn打开,你会发现网络又可以登录了。 方法一 注意:方法一虽然方便,但是可能会有

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测 目录 时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测基本介绍程序设计参考资料 基本介绍 MATLAB实现LSTM时间序列未来多步预测-递归预测。LSTM是一种含有LSTM区块(blocks)或其他的一种类神经网络,文献或其他资料中LSTM区块可能被描述成智能网络单元,因为