个人论坛系统测试报告

209 阅读19分钟

一、项目介绍

基于Spring前后端分离的博客论坛系统,实现了注册、登录、显示帖子、编辑帖子、删除帖子、回复帖子、点赞帖子,修改个人信息等功能,并将其部署到云服务器上。

技术要点:

  1. 使用统一返回格式+全局错误信息定义前后端交互时的返回结果;
  2. 使用@ControllerAdvice+@ExceptionHandler实现全局异常处理;
  3. 使用拦截器实现用户登录校验等页面过滤功能;
  4. 使用MD5和UUID等加密算法对用户密码进行加密,提高系统的安全性和数据保护能力;
  5. 使用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 功能测试:

whiteboard_exported_image.png

1.2.2 非功能测试:

whiteboard_exported_image (1).png

1.3.部分功能测试

1.3.1 对注册页面进行测试

  • 场景1:

输入用户名存在,密码与确认密码一致,点击注册

预期结果:提示用户已经存在

实际结果:提示用户已经存在,与预期结果一致。

image.png

  • 场景2:

输入用户名不存在,密码与却密码一致,点击注册

预期结果:注册成功,跳转回登录界面

实际结果:注册成功,跳转回登录界面,与预期结果一致。

1.3.2 对登录界面进行测试

  • 场景1:

输入用户名存在,密码与确认密码一致,点击登录

预期结果:登录成功,跳转到首页博客列表页面

实际结果:与预期结果一致。

image.png

  • 场景2:

输入用户名存在,密码与确认密码不一致,点击登录

预期结果:登录失败,给出错误提示

实际结果:登录失败,给出错误提示。

image.png

1.3.3 对首页进行测试

  • 场景1:

登录状态下,点击首页

预期结果:导航栏显示所有的版块名,下方显示所有帖子列表,右上方显示登录用户信息。

实际结果:与预期结果一致。

image.png

  • 场景2:

登录状态下,点击前端技术, 预期结果:下方显示C++名称,该版块下的帖子数量,版块下的所有帖子列表,右上方显示登录用户信息。

实际结果:与预期结果一致。

image.png

  • 场景3:

登录状态下,在搜索框输入关键字“数据库”搜索

预期结果:下方显示帖子正文中所有存在“数据库”这三个字的帖子;

实际结果:刷新回到首页界面,与预期不符。不支持搜索功能。

  • 场景4:

登录状态下,点击“月亮”按钮

预期结果:进入夜间模式的切换

实际结果:进入夜间模式的切换,与预期相符。

image.png

  • 场景5

登录状态下,点击“发布帖子”按钮

预期结果:进入博客编辑页面,版块名默认选择Java

实际结果:与预期相符。

image.png

1.3.4 对编辑帖子页面进行测试

  • 场景1:

未登录状态下,进入编辑页面

预期结果:跳转回登录界面

实际结果:跳转回登录界面,与预期结果一致。

  • 场景2:

登录状态下,不输入帖子标题,输入帖子内容,点击发布

预期结果:给出提示:请输入帖子标题

实际结果:与预期相符。

image.png

  • 场景3:

登录状态下,输入帖子标题,输入帖子内容,点击发布

预期结果:编辑成功,跳转回首页,最上方显示刚发布的帖子信息

实际结果:与预期相符。

image.png

1.3.5 对帖子详情页面进行测试

  • 场景1:

登录状态下,点击首页下的一条帖子内容“测试博客内容”

预期结果:跳转到该帖子详情页面,当前帖子是作者发布的,出现编辑和删除按钮

实际结果:与预期相符。

image.png

  • 场景2:

登录状态下,点击首页下的一条帖子内容“哈哈哈哈哈哈哈哈”(帖子作者“小白”,当前登录作者“1234”)

预期结果:跳转到该帖子详情页面,最上方显示帖子信息,左侧显示帖子作者信息,下方显示该帖子的内容,下方只显示点赞按钮。

实际结果:与预期相符。

image.png

  • 场景3:

登录状态下,下方点赞按钮

预期结果:上方显示的点赞数加1

实际结果:与预期相符。

image.png

  • 场景4:

登录状态下,点击首页下的一条帖子内容“123”,观察访问数变化

预期结果:跳转到该帖子详情页面,最上方显示帖子信息中的访问数+1

实际结果:与预期相符。

  • 场景5:

登录状态下,点击发私信按钮,不输入文本内容,点击“发送”

预期结果:给出警告提示:请输入要发送的内容

实际结果:与预期相符。

  • 场景6

登录状态下,点击发私信按钮,输入文本内容,点击“发送”

预期结果:给出成功提示,发送成功

实际结果:与预期相符。

image.png

image.png

  • 场景7

登录状态下,在下方的回复框中不输入文本内容,点击“回复”

预期结果:给出警告提示,请输入回复内容

实际结果:与预期相符。

image.png

  • 场景8

登录状态下,在下方的回复框中输入文本内容,点击“回复”

预期结果:给出成功提示,同时下方显示回复内容。

实际结果:与预期相符。

image.png

1.3.6 对个人中心页面进行测试

  • 场景1

未登录状态下,点击首页下的任意一条帖子内容

预期结果:跳转回登录界面

实际结果:跳转回登录界面,与预期结果一致。

  • 场景2 登录状态下,点击“我的帖子”

预期结果:下方显示该登录用户的所有帖子信息

实际结果:与预期相符。

image.png

  • 场景3

登录状态下,点击“个人中心”

预期结果:下方显示该登录用户的所有信息

实际结果:与预期相符。

image.png

  • 场景4

登录状态下,“修改昵称”

预期结果:输入修改后的昵称,并刷新成功

实际结果:与预期一致。

  • 场景5

登录状态下,“修改密码”:原密码错误,新密码和确认密码一致,点击修改密码

预期结果:给出警告提示:原密码有误。

实际结果:输出后端具体代码信息,与预期不一致。

image.png .................

这里只给出部分测试,其它功能就不一一测试了。

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();
    }
}

image.png

image.png

2.1.2 验证注册失败的情况
  • 场景1:

注册用户名在数据库存在,昵称,两次密码一致,注册失败,获取警告框信息。

代码同上。

测试结果

image.png

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();
    }
}

image.png

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);
       
    }
}

image.png

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);
    }
}

未登录,跳转回登录界面

image.png

  • 场景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);

}

image.png

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();
    }
}

image.png

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();
}

image.png

image.png

  • 场景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"));
}

image.png

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);

}

image.png

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));
    }
}

image.png

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);
}

测试结果: image.png

场景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("昵称修改成功!");

}

image.png

image.png

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);
    }
}

image.png

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;
}

image.png

image.png

脚本录制通过

3.2 使用Controller

3.2.1 创建性能测试场景

一次初始化5个用户,每隔1秒初始化一个虚拟用户

ea0c4b0b75804629546d1395e370325.png

设置虚拟用户数量10个,每隔1秒启动5个用户

fde885a454d71156c76424fabf0e083.png

运行时间设置3分钟

dfd02e5b70114a744b3a439add3c8cb.png

退出所有用户,每隔1秒退出1个用户

0fb07558d21fe26b28d6fff36967ee1.png

3.2.2点击运行,启动场景

0ff62d70ab17a95896e3ee5e4a08c80.png

运行过程截图:

3ceca3ec7d72d55b11692e25532b2c0.png

3.3 生成测试报告

714ab58402e754bd9098cfefc02dfe3.png 点击率

2ff944080c1c6321b7168364daf69af.png 吞吐量:

点击数越多,要处理的请求数量越多

adc0ac10be85dbe5f73c43ce6df1fb7.png