个人博客系统测试报告

news2025/4/28 13:11:51

文章目录

  • 一、功能测试
    • 1.编写测试用例
    • 2.总结测试后发现的BUG
  • 二、UI自动化测试
    • 0.搭建测试环境
    • 1. 创建公共类
    • 2.注册页面UI自动化测试用例编写
    • 3.登录页面UI自动化测试用例编写
    • 4.用户博客列表页面自动化测试
    • 5. 修改个信息页面
    • 6. 文章编辑页面
    • 7. 设置密保问题
      • 发现bug
    • 8. 所有用户文章列表页
    • 9. 总结
  • 三、性能测试
    • 1.编写性能测试脚本
      • 设置参数化
    • 2.创建测试场景
    • 3.开始执行
      • 简单分析性能测试报告
        • 运行的虚拟用户图表
        • 点击率表
        • 吞吐量表
        • 平均事务响应时间图
        • 系统资源图表


一、功能测试

1.编写测试用例

在这里插入图片描述

2.总结测试后发现的BUG

通过一系列的测试发现项目的以下bug:

  • 上传图片功能
    上传图片格式不正确直接跳转而没有提示,且图片格式校验不严谨
  • 发布博客测试
    文章正文为空,没有提示文章内容为空
  • 修改文章
    在修改文章时点击保存草稿没有做校验提示错误
  • 修改密码
    原密码错误,提示有问题
  • 找回密码
    未提示验证码错误,新密码格式为空
  • 博客列表页
    未简略显示文章正文字数过多问题

二、UI自动化测试

0.搭建测试环境

使用Junit5+selenium对项目进行简单的自动化测试。

引入Junit5和selenium依赖

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.8.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.junit.platform</groupId>
    <artifactId>junit-platform-suite</artifactId>
    <version>1.8.2</version>
    <scope>test</scope>
</dependency>
<dependency>
          <groupId>org.seleniumhq.selenium</groupId>
          <artifactId>selenium-java</artifactId>
          <version>4.0.0</version>
</dependency>
<!-- 文件保存相关 -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>

为了方便自动化测试,这里关闭了项目的验证码功能。

1. 创建公共类

为了避免在使用时频繁创建Chrome驱动类,我们可以定义一个功能类使用单例创建驱动对象。公共类里包含了保存截图的方法,方便测试截图观察。

public class AutoTestUtil {
    private static volatile ChromeDriver driver;
    private static final String IMG_SAVE_DIR = "./src/img/";
    private AutoTestUtil(){}
    public static ChromeDriver getDriver() {
        if (driver == null) {
            synchronized (AutoTestUtil.class) {
                if (driver == null) {
                    ChromeOptions options = new ChromeOptions();
                    options.addArguments("--remote-allow-origins=*");
                    driver = new ChromeDriver(options);
                    // 设置隐式等待
                    driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
                }
            }
        }
        return driver;
    }

    /**
     * 获取格式化时间
     * @return
     */
    private static List<String> getTime() {
        // 图片文件按照 包名.类名.方法名_时间搓区分
        SimpleDateFormat fileFormat = new SimpleDateFormat("yyyyMMdd-HHmmssSS");
        // 图片目录按照天区分格式20230812
        SimpleDateFormat dirFormat = new SimpleDateFormat("yyyyMMdd");

        String fileName = fileFormat.format(System.currentTimeMillis());
        String dirName = dirFormat.format(System.currentTimeMillis());
        List<String> result = new ArrayList<>();
        result.add(dirName);
        result.add(fileName);
        return result;
    }

    /**
     * 截图
     * @param testFuncName 对应函数名
     * @throws IOException
     */
    public static void saveFileImg(String testFuncName) throws IOException {
        List<String> times = getTime();
        String fileName = IMG_SAVE_DIR+times.get(0)+"/"+ testFuncName+"_"+times.get(1)+".png";
        File file = driver.getScreenshotAs(OutputType.FILE);
        FileUtils.copyFile(file,new File(fileName));
    }
}

2.注册页面UI自动化测试用例编写

在这里插入图片描述

在该测试中发现问题,找不到警告弹窗。异常信息:
在这里插入图片描述

因为我这里是采用的隐式等待,隐式等待是对弹窗不起作用的,代码执行过快就会出现代码执行到点击弹窗确定按钮,而弹窗还没有出现。所以在点击之前将一个1秒的强制等待即可解决问题。
在这里插入图片描述
编写测试代码:

  • 通过@TestMethodOrder(MethodOrderer.OrderAnnotation.class)保证测试用例的执行顺序
  • 对应的多个异常注册测试用例
  • 一个成功注册测试用例,通过检测是否跳转登录页面来判断是否注册成功
// 使用方法排序
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class RegAutoTest {
    private static ChromeDriver driver;

    @BeforeAll
    static void init() {
        driver = AutoTestUtil.getDriver();
        driver.get("http://120.25.124.200:7070/register.html");
        driver.manage().window().maximize();
    }

    /**
     * 检查注册页面是否正确打开
     * 检测点:注册账号按钮是否显示
     */
    @Test
    @Order(1)
    void regCheckLoad() {
        driver.findElement(By.xpath("//*[@id=\"reg_submit\"]"));
    }

    /**
     * 异常注册
     * @param username
     * @param password
     * @param confirmPass
     */
    @ParameterizedTest
    @Order(2)
    @CsvSource({"null,admin,admin","admin,null,admin","admin,admin,null","admin,admin,add","hhy,hhy,hhy"})
    void regFail(String username,String password,String confirmPass) throws InterruptedException {
        WebElement usernameElement = driver.findElement(By.cssSelector("#reg_username"));
        WebElement passwordElement = driver.findElement(By.xpath("//*[@id=\"reg_password\"]"));
        WebElement confirmPassElement = driver.findElement(By.cssSelector("#confirm_pass"));

        if (!username.equals("null")) {
            usernameElement.sendKeys(username);
        }
        if (!password.equals("null")) {
            passwordElement.sendKeys(password);
        }
        if (!confirmPass.equals("null")) {
            confirmPassElement.sendKeys(confirmPass);
        }
        driver.findElement(By.xpath("//*[@id=\"reg_submit\"]")).click();
        Thread.sleep(2000);
        // 点击警告弹窗的确认按钮
        Alert alert = driver.switchTo().alert();
        alert.accept();
        usernameElement.clear();
        passwordElement.clear();
        confirmPassElement.clear();
    }

    /**
     * 正常注册
     * @param username
     * @param password
     * @param confirmPass
     */
    @Order(3)
    @ParameterizedTest
    @CsvSource({"admin,admin,admin"})
    void regSuccess(String username,String password,String confirmPass) throws InterruptedException {
        driver.findElement(By.cssSelector("#reg_username")).sendKeys(username);
        driver.findElement(By.cssSelector("#reg_password")).sendKeys(password);
        driver.findElement(By.xpath("//*[@id=\"confirm_pass\"]")).sendKeys(confirmPass);
        driver.findElement(By.cssSelector("#reg_submit")).click();
        // 检测登录页面的元素来判断是否注册成功跳转
        // 检测登录按钮+注册连接
        driver.findElement(By.xpath("//*[@id=\"submit\"]"));
        driver.findElement(By.xpath("/html/body/div[2]/div[5]/a[1]"));
        Thread.sleep(1500);
    }

    @AfterAll
    static void quit() {
        driver.quit();
    }

}

自动化测试演示
在这里插入图片描述

执行完毕后7个用列全部完成
在这里插入图片描述

3.登录页面UI自动化测试用例编写

在这里插入图片描述

根据测试用例编写对应代码:

  • 通过截图查看是否进入博客列表页面
  • 使用套件执行自动化测试代码
@Suite
@SelectClasses(LogInAutoTest.class)
public class RunSuite {
}
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class LogInAutoTest {
    private static ChromeDriver driver;

    @BeforeAll
    static void init() {
        driver = AutoTestUtil.getDriver();
        driver.get("http://120.25.124.200:7070/login.html");
        driver.manage().window().maximize();
    }

    /**
     * 检测登录页面是否正确打开
     * 检测点:注册链接、登录按钮
     */
    @Test
    @Order(1)
    void loginCheckLoad() {
        driver.findElement(By.xpath("/html/body/div[2]/div[5]/a[1]"));
        driver.findElement(By.xpath("//*[@id=\"submit\"]"));
    }

    /**
     * 正常登录
     * @param username
     * @param password
     */
    @ParameterizedTest
    @CsvSource({"admin,admin","hhy,hhy"})
    @Order(3)
    void loginSuccess(String username,String password) throws IOException, InterruptedException {
        driver.findElement(By.xpath("//*[@id=\"username\"]")).sendKeys(username);
        driver.findElement(By.cssSelector("#password")).sendKeys(password);
        driver.findElement(By.xpath("//*[@id=\"submit\"]")).click();
        // 强制等待避免误截图
        Thread.sleep(1000);
        //将登录成功后的用户博客列表页面进行截图
        AutoTestUtil.saveFileImg(getClass().getName());
        driver.findElement(By.xpath("/html/body/div[1]/span[4]/a[3]")).click();

        Thread.sleep(1000);
        Alert alert = driver.switchTo().alert();
        alert.accept();
        Thread.sleep(1000);
        alert.accept();
    }

    /**
     * 异常登录
     * @param username
     * @param password
     */
    @ParameterizedTest
    @CsvSource({"null,null","null,admin","admin,null","admin,123","hello,000"})
    @Order(2)
    void loginFail(String username,String password) throws InterruptedException {
        WebElement usernameElement = driver.findElement(By.xpath("//*[@id=\"username\"]"));
        WebElement passwordElement = driver.findElement(By.cssSelector("#password"));
        if (!"null".equals(username)) {
            usernameElement.sendKeys(username);
        }
        if (!"null".equals(password)) {
            passwordElement.sendKeys(password);
        }
        driver.findElement(By.xpath("//*[@id=\"submit\"]")).click();
        // 强制等待防止弹窗未出现
        Thread.sleep(1000);
        Alert alert = driver.switchTo().alert();
        alert.accept();
        usernameElement.clear();
        passwordElement.clear();
    }

    @AfterAll
    static void quit() {
        driver.quit();
    }
}

自动化执行演示:
在这里插入图片描述
登录自动化执行完毕后,8个用例全部执行成功,保存了用户博客列表页面的截图。
在这里插入图片描述

4.用户博客列表页面自动化测试

在这里插入图片描述

  • 未登录的情况下通过检测url是否是登录页面来判断是否跳转
  • 正常登录场景下通过直接访问博客列表后,判断是否存在写博客链接和文章标题判断是否正确打开
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class UserBlogListAutoTest {
    private static ChromeDriver driver;

    @BeforeAll
    static void init() {
        driver = AutoTestUtil.getDriver();
        driver.manage().window().maximize();
    }

    /**
     * 未登录访问
     */
    @Test
    @Order(1)
    void userBlogListFail()  {
        driver.get("http://120.25.124.200:7070/user_blog_list.html");
        // 获取当前页面url,判断未登录情况下是否跳转
        String url = driver.getCurrentUrl();
        Assertions.assertEquals("http://120.25.124.200:7070/login.html",url);
    }

    /**
     * 进行正确登录
     * @param username
     * @param password
     */
    @ParameterizedTest
    @CsvSource({"admin,admin"})
    @Order(2)
    void loginSuccess(String username,String password) {
        driver.findElement(By.xpath("//*[@id=\"username\"]")).sendKeys(username);
        driver.findElement(By.cssSelector("#password")).sendKeys(password);
        driver.findElement(By.xpath("//*[@id=\"submit\"]")).click();

    }

    /**
     * 登录后访问
     * 检测点:写博客链接,用户文章标题
     */
    @Test
    @Order(3)
    void userBlogListSuccess() {
        driver.get("http://120.25.124.200:7070/user_blog_list.html");
        driver.findElement(By.xpath("/html/body/div[1]/span[4]/a[2]"));
        driver.findElement(By.cssSelector("body > div.content > div.mid > div.show > div > h4"));
    }

    @AfterAll
    static void quit() throws InterruptedException {
        // 注销
        driver.findElement(By.xpath("/html/body/div[1]/span[4]/a[3]")).click();
        Thread.sleep(1000);
        Alert alert = driver.switchTo().alert();
        alert.accept();
        Thread.sleep(1000);
        alert.accept();
        driver.quit();
    }
}

自动化演示:
在这里插入图片描述

5. 修改个信息页面

在这里插入图片描述

在进行修改信息页面测试时,发现无法找到昵称输入框,已经做了隐式等待。排查发现修改信息是在新窗口打开的,所以要通过代码切换窗口来处理。
在这里插入图片描述
通过句柄跳转到用户个人信息页面

// 获取博客列表页面句柄
        String windows = driver.getWindowHandle();
        // 点击修改资料链接
        driver.findElement(By.xpath("/html/body/div[2]/div[2]/div[1]/div[3]/a")).click();
        // 获取所有页面句柄
        Set<String> windowHandles = driver.getWindowHandles();
        for (String s : windowHandles) {
            if (!s.equals(windows)) {
                // 切换到用户信息页面
                driver.switchTo().window(s);
            }
        }

自动化测试代码:

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class UpdateUserInfoAutoTest {
    private static ChromeDriver driver;

    @BeforeAll
    static void init() {
        driver = AutoTestUtil.getDriver();
    }

    /**
     * 未登录状态下访问用户信息修改页面
     */
    @Test
    @Order(1)
    void updateUserInfoFail() {
        driver.get("http://120.25.124.200:7070/updateInfo.html");
        driver.manage().window().maximize();
    }


    /**
     * 进行正确登录
     * @param username
     * @param password
     */
    @ParameterizedTest
    @CsvSource({"admin,admin"})
    @Order(2)
    void loginSuccess(String username,String password) {
        driver.findElement(By.xpath("//*[@id=\"username\"]")).sendKeys(username);
        driver.findElement(By.cssSelector("#password")).sendKeys(password);
        driver.findElement(By.xpath("//*[@id=\"submit\"]")).click();
    }

    /**
     * 登录成功场景,修改个人昵称
     */
    @Order(3)
    @Test
    void updateUserInfoSuccess() throws InterruptedException {
        // 获取博客列表页面句柄
        String windows = driver.getWindowHandle();
        // 点击修改资料链接
        driver.findElement(By.xpath("/html/body/div[2]/div[2]/div[1]/div[3]/a")).click();
        // 获取所有页面句柄
        Set<String> windowHandles = driver.getWindowHandles();
        for (String s : windowHandles) {
            if (!s.equals(windows)) {
                // 切换到用户信息页面
                driver.switchTo().window(s);
            }
        }
        Thread.sleep(1000);
        // 修改基本信息
        driver.findElement(By.cssSelector("#netName")).clear();
        driver.findElement(By.cssSelector("#netName")).sendKeys("网友");
        // 提交修改
        driver.findElement(By.xpath("//*[@id=\"submitInfo\"]")).click();
        // 点击弹窗确认按钮
        Thread.sleep(1000);
        Alert alert = driver.switchTo().alert();
        alert.accept();
    }

    /**
     * 登录状态上传头像错误格式,大小错误
     */
    @Order(4)
    @ParameterizedTest
    @CsvSource({"C:\\Users\\HeHanYu\\Desktop\\code\\test.txt","C:\\Users\\HeHanYu\\Desktop\\壁纸\\wallhaven-d6eylg.jpg"})
    void updateUserPhotoFail(String filePath) throws InterruptedException {
        // 获取文件上传按钮
        WebElement element = driver.findElement(By.cssSelector("#uploadImg"));
        // 指定路径选择文件
        element.sendKeys(filePath);
        // 点击上传头像
        driver.findElement(By.xpath("//*[@id=\"submit\"]")).click();
        Thread.sleep(800);
        // 回退
        driver.navigate().back();
    }

    /**
     * 头像上传成功
     * @throws InterruptedException
     */
    @Order(5)
    @Test
    void updateUserPhotoSuccess() throws InterruptedException {
        // 获取文件上传按钮
        WebElement element = driver.findElement(By.xpath("//*[@id=\"uploadImg\"]"));
        // 指定路径选择文件
        element.sendKeys("C:\\Users\\HeHanYu\\Desktop\\code\\Python.jpg");
        Thread.sleep(1500);
        // 点击上传头像
        driver.findElement(By.xpath("//*[@id=\"submit\"]")).click();
        // 回退
        driver.navigate().back();
        
    }

    @AfterAll
    static void quit() throws InterruptedException {
        // 注销
        driver.findElement(By.xpath("/html/body/div[1]/span[4]/a[3]")).click();
        Thread.sleep(1000);
        Alert alert = driver.switchTo().alert();
        alert.accept();
        Thread.sleep(1000);
        alert.accept();
        driver.quit();
    }

}

自动测试执行完成后,测试用例全部通过

在这里插入图片描述

自动化测试演示:
在这里插入图片描述

6. 文章编辑页面

在这里插入图片描述

根据用例编写代码

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class ArticleEditorAutoTest {
    private static ChromeDriver driver;

    @BeforeAll
    static void init() {
        driver = AutoTestUtil.getDriver();
    }

    /**
     * 未登录访问
     */
    @Order(1)
    @Test
    void notLogin() {
        driver.get("http://120.25.124.200:7070/blog_editor.html");
    }

    /**
     * 进行正确登录
     * @param username
     * @param password
     */
    @ParameterizedTest
    @CsvSource({"admin,admin"})
    @Order(2)
    void loginSuccess(String username,String password) {
        driver.findElement(By.xpath("//*[@id=\"username\"]")).sendKeys(username);
        driver.findElement(By.cssSelector("#password")).sendKeys(password);
        driver.findElement(By.xpath("//*[@id=\"submit\"]")).click();
    }


    /**
     * 正确登录场景下打开
     * 检测点文章标题输入框是否存在
     */
    @Order(3)
    @Test
    void openArticleEditor() {
        // 点击写博客链接
        driver.findElement(By.cssSelector("body > div.nav > span.links > a:nth-child(2)"));
        // 直接输入url
        driver.get("http://120.25.124.200:7070/blog_editor.html");
        driver.manage().window().maximize();
        // 检测页面是否正确打开
        driver.findElement(By.cssSelector("#title"));
    }


    /**
     * 错误发布示例
     * @param title
     * @throws InterruptedException
     */
    @ParameterizedTest
    @CsvSource({"null"})
    @Order(4)
    void postFail(String title) throws InterruptedException {
        if (!"null".equals(title)) {
            driver.findElement(By.cssSelector("#title")).sendKeys(title);
        }

        driver.findElement(By.xpath("/html/body/div[2]/div[1]/button[1]")).click();
        Thread.sleep(800);
        Alert alert = driver.switchTo().alert();
        alert.accept();
    }

    @ParameterizedTest
    @CsvSource({"博客标题"})
    @Order(5)
    void postSuccess(String title) throws InterruptedException {
        driver.findElement(By.cssSelector("#title")).sendKeys(title);

        driver.findElement(By.xpath("/html/body/div[2]/div[1]/button[1]")).click();
        Thread.sleep(800);
        Alert alert = driver.switchTo().alert();
        alert.accept();
    }

    @AfterAll
    static void quit() {
        driver.quit();
    }

}

自动化演示:
在这里插入图片描述

博客发布页面自动化测试用例全部通过
在这里插入图片描述

7. 设置密保问题

在这里插入图片描述

  • 通过执行对应的错误测试用例
  • 执行正确的测试用例设置密保问题后,去找回密码页面获取密保问题

代码编写:

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class SetQuestionPasswordAutoTest {
    private static ChromeDriver driver;
    @BeforeAll
    static void init() {
        driver = AutoTestUtil.getDriver();
    }

    /**
     * 未登录状态下访问
     */
    @Order(1)
    @Test
    void notLogin() {
        driver.get("http://120.25.124.200:7070/set_questionPass.html");
        driver.manage().window().maximize();
    }

    /**
     * 进行正确登录进入到修改密码页面
     * @param username
     * @param password
     */
    @ParameterizedTest
    @CsvSource({"admin,admin"})
    @Order(2)
    void loginSuccess(String username,String password) throws InterruptedException {
        driver.findElement(By.xpath("//*[@id=\"username\"]")).sendKeys(username);
        driver.findElement(By.cssSelector("#password")).sendKeys(password);
        driver.findElement(By.xpath("//*[@id=\"submit\"]")).click();
        Thread.sleep(500);
        driver.get("http://120.25.124.200:7070/set_questionPass.html");
    }

    /***
     * 错误设置
     * @param password
     * @param answerOne
     * @param answerTwo
     * @param answerThree
     * @throws InterruptedException
     */
    @ParameterizedTest
    @CsvSource({"null,one,two,three","test,one,two,null","test,one,null,three","test,null,two,three","test,one,two,three"})
    @Order(3)
    void setQuestionPassFail(String password,String answerOne,String answerTwo,String answerThree) throws InterruptedException {
        WebElement passElement = driver.findElement(By.xpath("//*[@id=\"password\"]"));
        WebElement oneElement = driver.findElement(By.cssSelector("#oneValue"));
        WebElement twoElement = driver.findElement(By.xpath("//*[@id=\"twoValue\"]"));
        WebElement threeElement = driver.findElement(By.xpath("//*[@id=\"threeValue\"]"));

        if (!"null".equals(password)) {
            passElement.sendKeys(password);
        }
        if (!"null".equals(answerOne)) {
            oneElement.sendKeys(answerOne);
        }
        if (!"null".equals(answerTwo)) {
            twoElement.sendKeys(answerTwo);
        }
        if (!"null".equals(answerThree)) {
            threeElement.sendKeys(answerThree);
        }
        // 获取Select问题标签
        Select selectOne = new Select(driver.findElement(By.xpath("//*[@id=\"one\"]")));
        Select selectTwo = new Select(driver.findElement(By.xpath("//*[@id=\"two\"]")));
        Select selectThree = new Select(driver.findElement(By.xpath("//*[@id=\"three\"]")));
        // 选取问题
        selectOne.selectByIndex(1);
        selectTwo.selectByIndex(1);
        selectThree.selectByIndex(1);

        //提交
        driver.findElement(By.xpath("//*[@id=\"reg_submit\"]")).click();
        // 点击弹窗确认按钮
        Thread.sleep(500);
        driver.switchTo().alert().accept();
        // 清空输入框
        passElement.clear();
        oneElement.clear();
        twoElement.clear();
        threeElement.clear();
    }

    /***
     * 正确设置
     * @param password
     * @param answerOne
     * @param answerTwo
     * @param answerThree
     * @throws InterruptedException
     */
    @ParameterizedTest
    @CsvSource({"admin,one,two,three"})
    @Order(3)
    void setQuestionPassSuccess(String password,String answerOne,String answerTwo,String answerThree) throws InterruptedException {

        WebElement passElement = driver.findElement(By.xpath("//*[@id=\"password\"]"));
        WebElement oneElement = driver.findElement(By.cssSelector("#oneValue"));
        WebElement twoElement = driver.findElement(By.xpath("//*[@id=\"twoValue\"]"));
        WebElement threeElement = driver.findElement(By.xpath("//*[@id=\"threeValue\"]"));

        // 填写密码和问题
        passElement.sendKeys(password);
        oneElement.sendKeys(answerOne);
        twoElement.sendKeys(answerTwo);
        threeElement.sendKeys(answerThree);

        // 获取Select问题标签
        Select selectOne = new Select(driver.findElement(By.xpath("//*[@id=\"one\"]")));
        Select selectTwo = new Select(driver.findElement(By.xpath("//*[@id=\"two\"]")));
        Select selectThree = new Select(driver.findElement(By.xpath("//*[@id=\"three\"]")));
        // 选取问题
        selectOne.selectByIndex(1);
        selectTwo.selectByIndex(1);
        selectThree.selectByIndex(1);

        //提交
        driver.findElement(By.xpath("//*[@id=\"reg_submit\"]")).click();

    }

    /**
     * 检测问题是否设置成功
     */
    @Test
    @Order(4)
    void checkSetQuestion() throws InterruptedException {
        driver.get("http://120.25.124.200:7070/find_pass.html");
        Thread.sleep(1000);
        driver.switchTo().alert().accept();
        System.out.println(driver.getCurrentUrl());
        driver.findElement(By.xpath("//*[@id=\"username\"]")).sendKeys("admin");
        driver.findElement(By.cssSelector("#reg > div:nth-child(1) > button")).click();
        String answer = driver.findElement(By.xpath("//*[@id=\"one\"]")).getText();
        System.out.println(answer);
        // 如果获取到了问题说明设置密保问题就成功了
        Assertions.assertNotEquals("问题1",answer);
    }

    @AfterAll
    static void quit() {
        driver.quit();
    }
}

自动化演示:
在这里插入图片描述

发现bug

在这里插入图片描述
设置获取的密保问题的断言执行了。
在执行多次设置密保问后都设置成功了,但是在验证通过密保问题找回密码时,发生了错误。

在这里插入图片描述
通过查看数据库的问题表发现了问题:
同一个用户有多个问题存在数据表中,原因是设置密保问题时没有对已经设置过密保的用户进行校验。导致多次插入数据,引发查询到多条数据。
在这里插入图片描述

8. 所有用户文章列表页

在这里插入图片描述
在测试过程中发现为找到过期元素异常
在这里插入图片描述
发现是每次点击上一页或者下一页,页面都会刷新,所以导致元素失效,原理的代码如下

@Test
    void test() throws InterruptedException {
       WebElement first = driver.findElement(By.cssSelector("body > div:nth-child(3) > div > button.first"));
       WebElement last = driver.findElement(By.xpath("/html/body/div[3]/div/button[4]"));
       WebElement front = driver.findElement(By.xpath("/html/body/div[3]/div/button[2]"));
       WebElement next = driver.findElement(By.xpath("/html/body/div[3]/div/button[3]"));

       first.click();
       Thread.sleep(1000);
       driver.switchTo().alert().accept();
       front.click();
       Thread.sleep(1000);
       driver.switchTo().alert().accept();
       next.click();
        Thread.sleep(1000);
       front.click();
        Thread.sleep(1000);
       last.click();
        Thread.sleep(1000);
       next.click();
       Thread.sleep(1000);
       driver.switchTo().alert().accept();
       last.click();
       Thread.sleep(1000);
       driver.switchTo().alert().accept();


    }

改进代码,每次切换页面后重新获取元素

public class BlogListAutoTest {
    private static ChromeDriver driver;
    static WebElement first;
    static WebElement last;
    static WebElement front;
    static WebElement next;
    @BeforeAll
    static void init() {
        driver = AutoTestUtil.getDriver();
        driver.get("http://120.25.124.200:7070/blog_list.html");
        driver.manage().window().maximize();

    }

    void get() {
        first = driver.findElement(By.xpath("/html/body/div[3]/div/button[1]"));
        last = driver.findElement(By.xpath("/html/body/div[3]/div/button[4]"));
        front = driver.findElement(By.xpath("/html/body/div[3]/div/button[2]"));
        next = driver.findElement(By.xpath("/html/body/div[3]/div/button[3]"));
    }
    @Test
    void test() throws InterruptedException {
        get();
       first.click();
       Thread.sleep(1000);
       driver.switchTo().alert().accept();
       front.click();
       Thread.sleep(1000);
       driver.switchTo().alert().accept();
       next.click();
       get();
        Thread.sleep(1000);
       front.click();
       get();
        Thread.sleep(1000);
       last.click();
       get();
        Thread.sleep(1000);
       next.click();

       Thread.sleep(1000);
       driver.switchTo().alert().accept();

        get();
        last.click();

       Thread.sleep(1000);
       driver.switchTo().alert().accept();


    }

    @AfterAll
    static void quit() {
        driver.quit();
    }
}

自动化演示:

在这里插入图片描述

9. 总结

通过Junit5单元测试工具配合selenium4自动化工具有如下亮点(好处)

  1. 使用注解:避免生成过多对象,造成资源和时间的浪费
  2. 通过static修饰静态变量,全局只创建一次驱动对象,避免重复创建驱动对象造成时间的浪费
  3. 使用参数化:保持用例简洁,提高了代码的可读性
  4. 使用测试套件:一次性执行所有我们想要运行的自动化用例
  5. 使用等待(隐式等待+强制等待):提高自动化指定的稳定性(降低自动化出现误报的概率)
  6. 使用屏幕截图:方便问题的追溯和问题的解决

三、性能测试

使用LoadRunner对项目做一个简单的性能测试,性能测试在本机上进行测试,测试云服务器太麻烦。

登录和所有文章列表页面是高频使用场景,通过LoadRunner模拟多个用户进行并发进行登录后访问所有文章列表页面。

1.编写性能测试脚本

Action()
{
	
	//开启进入登录页事务
	lr_start_transaction("login_index");
    /* 注册获取返回参数,该方法可以配合打印返回数据,检测数据内容 */
	web_reg_save_param("ParaResult",
					   "LB=",
					   "RB=",
					   LAST);
    // 定时检查点,检测登录页面是否正确打开
    web_reg_find("Text=登录",LAST);
    // 定义虚拟用户结合点
    lr_rendezvous("start");
    // 进入登录页面
	web_url("login_html",
		"URL=http://127.0.0.1:7070/login.html",
		"TargetFrame=",
		"Resource=0",
		"Referer=",
		LAST);
    // 结束进入登录页事务
	lr_end_transaction("login_index", LR_AUTO);
	//开启登录事务
	lr_start_transaction("login");
    // 进行登录
	web_submit_data("login",
		"Action=http://127.0.0.1:7070/user/login",
		"Method=POST",
		"EncType=application/x-www-form-urlencoded; charset=UTF-8",
		"TargetFrame=",
		"Referer=",
		"Mode=HTTP",
		ITEMDATA,
		"Name=username", "Value=<username>", ENDITEM,
		"Name=password", "Value=<password>", ENDITEM,
		LAST);

    //定时检测所有文章列表页检查点
    web_reg_find("Text=查看全文",LAST);
    // 结束登录事务
	lr_end_transaction("login", LR_AUTO);
	
	//文章列表事务
	lr_start_transaction("blog_list");
    // 登录后访问所有文章列表页面
	web_url("blog_list",
		"URL=http://127.0.0.1:7070/blog_list.html",
		"TargetFrame=",
		"Resource=0",
		"Referer=",
		LAST);

    // 结束文章列表页事务
	lr_end_transaction("blog_list", LR_AUTO);
    


	return 0;
}

点击测试
在这里插入图片描述

测试脚本没有问题后修改Action脚本的执行次数,执行5次脚本
在这里插入图片描述

设置参数化

为了保证测试的合理性,多个虚拟用户使用多个不同的账号进行登录,使用LoadRunner的参数化即可实现。
在这里插入图片描述

2.创建测试场景

针对编写好的脚本通过Controller创建测试场景

1.设置15个虚拟用户
在这里插入图片描述

2.设置创建好测试场景后每5秒初始化3个虚拟用户
在这里插入图片描述

3.设置每5秒进入3个虚拟用户到测试场景
在这里插入图片描述
4.设置虚拟用户执行循环执行5分钟
在这里插入图片描述
5.设置虚拟用户执行完毕后每10秒退出5个虚拟用户
在这里插入图片描述
6.添加监视系统资源
CPU运行时间和剩余内存
在这里插入图片描述

3.开始执行

在这里插入图片描述

简单分析性能测试报告

在这里插入图片描述

在事务报告中,一般只关注平均值和标准方差,标准偏差值越大,说明越不稳定。而且脚本里值是写3个事务,而这里却有6个,因为每个文件就是一个事务脚本文件中的(init、action、end)
在这里插入图片描述

运行的虚拟用户图表

通过虚拟用户运行图标发现,在脚本运行40秒到5分30秒之间虚拟用户给了服务器负载

在这里插入图片描述

点击率表

通过点击率表可以看到和虚拟用户运行表运行对应起来,虚拟用户的增多点击率也随之增多,点击率越多说明和服务器的交互次数也越多。
在这里插入图片描述

吞吐量表

吞吐量图形和点击数图形有点相似,但是吞吐量的曲线会稍后延后一点递增。因为吞吐量表示的是响应返回的资源数量,所有是要先有请求才会有响应。

在这里插入图片描述

平均事务响应时间图

通过事务响应时间发现,访问登录页面的时间比较长,登录事务时间响应时间是比较短的,(深蓝是访问登录页面、黄色是登录事务、粉红色是进入文章列表页面),在40秒的时候事务的响应时间达到最大,那个时候正是15个虚拟用户生成完成,进行访问服务,导致一大波请求到达服务,导致事务响应时间长。
虚拟用户在性能测试过程中,每秒在服务器上命中的次数,通过次图可以帮助根据命中次数评估虚拟用户生成的负载量
在这里插入图片描述

系统资源图表

  • precessorTime:CPU使用时间,被消耗的处理器时间数量
  • Available MBytes:可用的物理内存,一般根据这个指标推算消耗的物理内存有多大。(已经消耗的物理内存=实际内存 - 可用物理内存)
    CPU的占用时间从30多秒开始,基本在长时间使用CPU,对CPU的使用时间还是长的。因为本地使用的是自己的电脑,而且并发设置了15,对于电脑压力还是比较大的。
    对应的这次测试对于内存的占用还不是特别高的。
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/876872.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QTreeView显示多级多列目录

效果图&#xff1a; 头文件&#xff1a; QStandardItemModel *m_treeMode;源文件 m_treeMode new QStandardItemModel(0,1,this);ui->treeView->setModel(m_treeMode);//控制第一列节点个数int mainLevel 3;for (int i 0; i < mainLevel; i) {QList<QStandar…

【设计模式】非GOF的常见设计模型

结构型模式 系列综述&#xff1a; 来源&#xff1a;该系列是主要参考《大话设计模式》和《设计模式(可复用面向对象软件的基础)》&#xff0c;其他详细知识点拷验来自于各大平台大佬的博客。 总结&#xff1a;设计模式汇总篇 如果对你有用&#xff0c;希望关注点赞收藏一波。 文…

无需停服!PostgreSQL数据迁移工具-NineData

PostgreSQL 是一种备受开发者和企业青睐的关系型数据库&#xff0c;其丰富的数据类型、地理空间负载和强大的扩展能力等特性使其备受欢迎。然而&#xff0c;在企业使用 PostgreSQL 承载应用的过程中&#xff0c;由于业务需要上云、跨云、下云、跨机房迁移、跨地域迁移、数据库版…

C语言学习笔记---操作符详解

C语言程序设计笔记---012 C语言操作符1、算数操作符1.1、算术操作符例程 2、移位操作符2.1、移位操作符例程12.2、移位操作符例程22.3、移位操作符例程3 3、位操作符3.1、位操作符例程13.2、位操作符例程23.3、位操作符例程3 --按位与&1扩展3.4、位操作符例程4 --按位异或^…

使用SpringAop切面编程通过Spel表达式实现Controller权限控制

目录 参考一、概念SpEL表达式 二、开发引入包定义注解定义切面定义用户上下文 三、测试新建Service在方法上注解新建Service在类上注解运行 参考 SpringBoot&#xff1a;SpEL让复杂权限控制变得很简单 一、概念 对于在Springboot中&#xff0c;利用自定义注解切面来实现接口…

LVGL学习笔记 30 - List(列表)

目录 1. 添加文本 2. 添加按钮 3. 事件 4. 修改样式 4.1 背景色 4.2 改变项的颜色 列表是一个垂直布局的矩形&#xff0c;可以向其中添加按钮和文本。 lv_obj_t* list1 lv_list_create(lv_scr_act());lv_obj_set_size(list1, 180, 220);lv_obj_center(list1); 部件包含&…

Linux命令200例:adduser用于创建新用户

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌。CSDN专家博主&#xff0c;阿里云社区专家博主&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &…

求Win11系统virtualbox+vagrant安装MacOS虚拟机

文章目录 一、背景二、素材2.1、virtualboxvagrant 三、问题3.1、安装失败3.2、第二个失败3.3、网络说 四、求助 一、背景 题主&#xff0c;主要是穷&#xff0c;没钱买mac笔记本或相关系统的苹果产品&#xff0c;哈哈&#xff0c;偶尔也有用过MacOS系统&#xff0c;只是还没有…

app专项测试:app弱网测试

目录 弱网测试背景 网络测试要点 弱网测试关注指标 弱网测试工具 fiddler模拟网络延时场景 网络设置参考 Network Emulator Toolkit模拟网络丢包场景&#xff08;windows网络&#xff09; APP弱网测试 弱网使用工具&#xff1a; app弱网测试要点 APP网络测试要点 网络…

OpenCV图像处理——模版匹配和霍夫变换

目录 模版匹配原理实现 霍夫变换霍夫线检测 模版匹配 原理 实现 rescv.matchTemplate(img,template,method)import numpy as np import cv2 as cv import matplotlib.pyplot as pltimgcv.imread(./汪学长的随堂资料/6/模板匹配/lena.jpg) templatecv.imread(./汪学长的随堂资…

一文搞懂Jenkins持续集成解决的是什么问题

1、持续集成的定义 大师 Martin Fowler 是这样定义持续集成的: 持续集成是一种软件开发实战, 即团队开发成员经常集成他们的工作. 通常, 每个成员每天至少集成一次, 也就意味着每天可能发生多次集成. 持续集成并不能消除Bug, 而是让它们非常容易发现和改正. 根据对项目实战的…

uniapp开发小程序-有分类和列表时,进入页面默认选中第一个分类

一、效果&#xff1a; 如下图所示&#xff0c;进入该页面后&#xff0c;默认选中第一个分类&#xff0c;以及第一个分类下的列表数据。 二、代码实现&#xff1a; 关键代码&#xff1a; 进入页面时&#xff0c;默认调用分类的接口&#xff0c;在分类接口里做判断&#xff…

Android 网络编程-网络请求

Android 网络编程-网络请求 文章目录 Android 网络编程-网络请求一、主要内容二、开发网络请求前的基本准备1、查看需要请求的网址是否有效&#xff08;1&#xff09;通过网页在线验证&#xff08;2&#xff09;使用专用window网咯请求工具&#xff08;3&#xff09;编写app代码…

less学习语法

1.CSS函数的补充 1.rgb/rgba/translate/rotate/scale 2.非常好用的css函数&#xff1a; var:使用css定义的变量calc:计算css值&#xff0c;通常用于计算元素的大小或位置blur:毛玻璃&#xff08;高斯模糊&#xff09;效果gradient:颜色渐变函数 var:定义变量 css中可以自定…

关于青少年学习演讲与口才对未来的领导力的塑造的探析

标题&#xff1a;青少年学习演讲与口才对未来领导力的塑造&#xff1a;一项探析 摘要&#xff1a; 本论文旨在探讨青少年学习演讲与口才对未来领导力的塑造的重要性和影响。通过分析演讲和口才对青少年的益处&#xff0c;以及如何培养这些技能来促进领导力的发展&#xff0c;我…

pytest数据驱动 pandas

pytest数据驱动 pandas 主要过程&#xff1a;用pandas读取excel里面的数据&#xff0c;然后进行百度查询&#xff0c;并断言 pf pd.read_excel(data_py.xlsx, usecols[1,2])print(pf.values)输出&#xff1a;[[‘听妈妈的话’ ‘周杰伦’] [‘遇见’ ‘孙燕姿’] [‘伤心太平…

win10下如何安装ffmpeg

安装ffmpeg之前先安装win10 绿色软件管理软件&#xff1a;scoop. Scoop的基本介绍 Scoop是一款适用于Windows平台的命令行软件&#xff08;包&#xff09;管理工具&#xff0c;这里是Github介绍页。简单来说&#xff0c;就是可以通过命令行工具&#xff08;PowerShell、CMD等…

性能优化-超大图加载

超大图加载优化 网站首页的头部有时候要加载超大图&#xff0c;可能超过4M&#xff0c;如果网速不好用户会看到好长时间的白屏&#xff0c;体验非常不好。 这里使用大图缩略图的模式处理这个问题&#xff1a; 使用工具根据大图(>1M)做一个10k的缩略图图片同时加载&#xf…

这所院校性价比极高!专业课太简单了!保护一志愿!

一、学校及专业介绍 昆明理工大学&#xff08;Kunming University of Science and Technology&#xff09;&#xff0c;位于云南省昆明市&#xff0c;是国防科技工业局与云南省共建的重点大学&#xff0c;国家"特色重点学科项目"建设高校。昆工就综合实力和竞争压力…