二次元Hub测试报告

一、项目背景

1.1 项目概述

本项目旨在构建一个基于Spring Boot、MyBatis、MySQL及Spring MVC技术栈的二次元论坛,为用户提供一个集内容创作、分享、交流于一体的在线平台。该系统将充分利用Spring Boot的便捷性简化项目配置与部署,结合MyBatis的高效数据库操作能力,以及Spring MVC的强大页面交互处理能力,共同打造一个功能完善、性能优良的论坛。

1.2项目名称

二次云论坛

1.3开发语言

Java

1.4开发环境

IntelliJ IDEA 2022.2.2 (Ultimate Edition)

JDK1.8.0

1.5自动化测试代码

https://github.com/muyangyo/SynchroProject/tree/main/JavaProject/webAutoTestFrame/src/main/java

二、项目主要页面及功能

2.1用户登录页面

http://127.0.0.1:8080/login.html

image

2.2论坛列表页

http://127.0.0.1:8080/blog_list.html

image

2.3文章详情页

http://127.0.0.1:8080/blog_detail.html

image

2.4文章编辑页

http://127.0.0.1:8080/blog_edit.html

image

2.5文章修改页

http://127.0.0.1:8080/blog_modify.html

image

2.6注册页

http://127.0.0.1:8080/register.html

image

三、对项目进行测试

3.1编写测试用例

3.1.1用户登录页面测试用例

image

3.1.2论坛列表页面测试用例

image

3.1.3文章详情页测试用例

image

3.1.4文章编辑页测试用例

image

3.1.5文章修改页测试用例

image

3.1.6注册页测试用例

image

3.2执行测试

首先要创建一个maven项目,引入selenium以及Junit5的依赖以及安装浏览器驱动依赖

<!-- Selenium WebDriver dependency -->
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>4.0.0</version>
        </dependency>

        <!-- WebDriverManager for automatic WebDriver management -->
        <dependency>
            <groupId>io.github.bonigarcia</groupId>
            <artifactId>webdrivermanager</artifactId>
            <version>5.8.0</version>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.9.1</version>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-params</artifactId>
            <version>5.9.1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-params -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-params</artifactId>
            <version>5.9.1</version>
        </dependency>
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-suite</artifactId>
            <version>1.9.1</version>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.junit.platform/junit-platform-suite -->
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-suite</artifactId>
            <version>1.9.1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.9.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.github.bonigarcia</groupId>
            <artifactId>webdrivermanager</artifactId>
            <version>5.8.0</version>
            <scope>compile</scope>
        </dependency>

创建Meta类,Sleep类,WaitStrategy枚举类,利用继承Meta类,简化代码,提高复用率

package Base;

import io.github.bonigarcia.wdm.WebDriverManager;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

import java.time.Duration;

/**
 * 创建于 IntelliJ IDEA.
 * 描述:
 * User: 沐阳Yo
 */
public class Meta {


    /**
     * 为什么这里使用的是静态呢? 因为避免new对象才进行初始化,直接调用就进行初始化
     */
    static {
        //使⽤插件管理⼯具webdrivermanager
        WebDriverManager.chromedriver().setup();
        //添加浏览器配置
        ChromeOptions options = new ChromeOptions();
        //允许任何来源的远程连接
        options.addArguments("--remote-allow-origins=*");
        driver = new ChromeDriver(options);
    }

    @RequiresInitialization
    public static void init(WaitStrategy strategy) {
        if (strategy.equals(WaitStrategy.INTELLIGENT_WAITING)) {
            //智能等待
            driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(2));//隐式等待2秒
        }
        sleep = new Sleep();
    }

    public static ChromeDriver driver;
    public static Sleep sleep;


    public static WebElement byCssGetElement(String cssSelector) {
        return driver.findElement(By.cssSelector(cssSelector));
    }

    public static WebElement byXpathGetElement(String xpath) {
        return driver.findElement(By.xpath(xpath));
    }
}

package Base;

public class Sleep {
    /**
     * 使当前线程暂停执行3000毫秒(3秒)
     */
    public void sleepLongTime() throws InterruptedException {
        Thread.sleep(3000);
    }

    /**
     * 使当前线程暂停执行1500毫秒(1.5秒)
     */
    public void sleepNormalTime() throws InterruptedException {
        Thread.sleep(1500);
    }

    /**
     * 使当前线程暂停执行500毫秒(0.5秒)
     */
    public void sleepShortTime() throws InterruptedException {
        Thread.sleep(500);
    }
}
package Base;

/**
 * 创建于 IntelliJ IDEA.
 * 描述:
 * User: 沐阳Yo
 */
public enum WaitStrategy {
    MANDATORY_WAIT, INTELLIGENT_WAITING;
}

再编写测试类 HubSystemTest 继承于 Meta 类,并且完成 Meta 类的初始化设置,和所有测试完成后的收尾工作

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class HubSystemTest extends Meta {
    static int anInt = 0;

    @BeforeAll
    static void Init() throws IOException {
        init(WaitStrategy.INTELLIGENT_WAITING);
		//利用文件进行存储该代码运行了多少次,便于后续注册站账号时使用
        File file = new File("./mark/mark.txt");
        if (!file.exists()) {
            FileUtils.touch(file);
        }

        try (InputStream inputStream = new FileInputStream(file);
             InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
             Scanner scanner = new Scanner(inputStreamReader)) {
            if (scanner.hasNextInt()) {
                anInt = scanner.nextInt();
            }
        }

        try (OutputStream outputStream = new FileOutputStream(file);
             OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
             PrintWriter printWriter = new PrintWriter(outputStreamWriter)) {
            printWriter.println(anInt + 1);
            printWriter.flush();
        }

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

编写注册自动化测试

 @ParameterizedTest
    @CsvSource({"'user','user'"})
    @Order(0)
    void registerTest(String newUsername, String newPassword) throws InterruptedException {
        newUsername = newUsername + anInt;
        newPassword = newPassword + anInt;

        driver.get("http://127.0.0.1:8080/");
        WebElement registerBtn = byCssGetElement("body > div.login-container > div > div:nth-child(4) > a");
        registerBtn.click();
        sleep.sleepNormalTime();
        Assertions.assertEquals("http://127.0.0.1:8080/register.html", driver.getCurrentUrl());
        WebElement username = byCssGetElement("#inputUsername");
        username.sendKeys(newUsername);
        WebElement password = byCssGetElement("#inputPassword");
        password.sendKeys(newPassword);
        WebElement rePassword = byCssGetElement("#inputREPassword");
        rePassword.sendKeys(newPassword + "1");
        WebElement submit = byCssGetElement("#registerButton");
        submit.click();
        sleep.sleepNormalTime();
        //验证如果密码不同是否会报错
        Alert alert = driver.switchTo().alert();
        Assertions.assertEquals("两次输入的密码不一致!", alert.getText());
        alert.accept();
        sleep.sleepNormalTime();

        //重新输入密码
        rePassword.clear();
        rePassword.sendKeys(newPassword);
        submit.click();
        sleep.sleepNormalTime();
        Alert alert1 = driver.switchTo().alert();
        Assertions.assertEquals("注册成功!", alert1.getText());
        alert1.accept();
    }

编写登入自动化测试

@ParameterizedTest
    @CsvFileSource(resources = "login.csv")
    @Order(1)
    void loginTest(String username, String password) throws InterruptedException {
        driver.get("http://127.0.0.1:8080/");
        WebElement usernameText = byCssGetElement("#username");
        usernameText.sendKeys(username);
        WebElement passwordText = byCssGetElement("#password");
        passwordText.sendKeys(password);
        WebElement submit = byCssGetElement("#submit");
        submit.click();
        sleep.sleepNormalTime();
        driver.switchTo().alert().accept();

        Assertions.assertEquals("http://127.0.0.1:8080/blog_list.html", driver.getCurrentUrl());
        Assertions.assertEquals(username, byCssGetElement("body > div.container > div.container-left > div > h3").getText());
    }

编写发布文章自动化测试

 @Test
    @Order(2)
    void publishBlogTest() throws InterruptedException {
        driver.get("http://127.0.0.1:8080/blog_list.html");
        WebElement a = byCssGetElement("body > div.nav > a:nth-child(5)");
        a.click();
        sleep.sleepNormalTime();
        WebElement title = byCssGetElement("#title-input");
        title.sendKeys("自动化测试生成文章");

        WebElement submit = byCssGetElement("#submit");
        submit.click();
        sleep.sleepShortTime();

        Alert alert = driver.switchTo().alert();
        Assertions.assertEquals("成功添加!", alert.getText());
        alert.accept();
    }

编写评论自动化测试

 @Test
    @Order(3)
    void commentTest() throws InterruptedException {
        driver.get("http://127.0.0.1:8080/blog_list.html");
        WebElement blog = byXpathGetElement("//div[text()='自动化测试生成文章']");
        blog.click();
        sleep.sleepNormalTime();
        WebElement text = byCssGetElement("body > div.container > div.container-left > div.commentArea > div > input");
        text.sendKeys("测试评论是否正常");
        WebElement btn = byCssGetElement("body > div.container > div.container-left > div.commentArea > div > button");
        btn.click();
        sleep.sleepNormalTime();
        Alert alert = driver.switchTo().alert();
        Assertions.assertEquals("成功添加评论!", alert.getText());
        alert.accept();
        sleep.sleepNormalTime();
        driver.navigate().refresh();
        sleep.sleepNormalTime();
        WebElement webElement = byXpathGetElement("//p[text()='测试评论是否正常']");
    }

编写修改文章自动化测试

 @Test
    @Order(4)
    void editBlogTest() throws InterruptedException {
        driver.get("http://127.0.0.1:8080/blog_list.html");
        WebElement blog = byXpathGetElement("//div[text()='自动化测试生成文章']");
        blog.click();
        sleep.sleepNormalTime();
        WebElement editBtn = byCssGetElement("body > div.container > div.container-left > div.card > button.edit-button");
        editBtn.click();
        sleep.sleepLongTime();
        WebElement title = byCssGetElement("#title-input");
        String text = title.getAttribute("value") + "修改后的";
        title.clear();
        title.sendKeys(text);
        WebElement submit = byCssGetElement("#submit");
        submit.click();
        sleep.sleepNormalTime();
        Alert alert = driver.switchTo().alert();
        Assertions.assertEquals("成功修改!", alert.getText());
        alert.accept();
        sleep.sleepNormalTime();
        WebElement newTitle = byCssGetElement("body > div.container > div.container-right > h3");
        Assertions.assertEquals(text, newTitle.getText());
    }

编写删除博客自动化测试

@Test
    @Order(5)
    void deleteBlogTest() throws InterruptedException {
        driver.get("http://127.0.0.1:8080/blog_list.html");
        WebElement blog = byXpathGetElement("//div[text()='自动化测试生成文章修改后的']");
        blog.click();
        sleep.sleepNormalTime();
        WebElement deleteBtn = byCssGetElement("body > div.container > div.container-left > div.card > button.delete-button");
        deleteBtn.click();
        sleep.sleepShortTime();
        Alert alert = driver.switchTo().alert();
        Assertions.assertEquals("成功删除!", alert.getText());
        alert.accept();
    }

编写登出自动化测试

@Test
    @Order(6)
    void logoutTest() throws InterruptedException {
        driver.get("http://127.0.0.1:8080/blog_list.html");
        WebElement logoutBtn = byCssGetElement("body > div.nav > a:nth-child(6)");
        logoutBtn.click();
        sleep.sleepNormalTime();
        Assertions.assertEquals("http://127.0.0.1:8080/login.html", driver.getCurrentUrl());

        //未登入状态下进入首页
        driver.get("http://127.0.0.1:8080/blog_list.html");
        Assertions.assertEquals("请先登录!", driver.switchTo().alert().getText());
        driver.switchTo().alert().accept();
        Assertions.assertEquals("http://127.0.0.1:8080/login.html", driver.getCurrentUrl());
    }

编写验证登录自动化测试

@ParameterizedTest
    @CsvSource({"'Demo','123'"})
    @Order(7)
    void errorLoginTest(String username, String password) throws InterruptedException {
        driver.get("http://127.0.0.1:8080/");
        WebElement usernameText = byCssGetElement("#username");
        usernameText.sendKeys(username);
        WebElement passwordText = byCssGetElement("#password");
        passwordText.sendKeys(password);
        WebElement submit = byCssGetElement("#submit");
        submit.click();
        sleep.sleepNormalTime();

        Alert alert = driver.switchTo().alert();
        Assertions.assertEquals("登录失败! 账号或者密码错误!", alert.getText());
        sleep.sleepNormalTime();
        alert.accept();
    }

三、测试总结

4.1测试分类

4.1.1功能测试

测试用例

功能测试结果:测试用例100%通过

4.1.2自动化测试

自动化测试模块覆盖:用户登录页面,用户注册页面,列表页面,文章详情页面,文章编辑页,文章修改页

自动化测试用例数量:8 个

自动化测试结果:

image

4.2遗留风险

测试时间紧张,先保证了Hub主体功能没有问题,可能存在细节测试不到位风险

4.3测试结果评估

(1) 部分页面未登入直接使用 URL 访问时,后端虽然检验权限不足,没有返回对应的数据,但是有的页面没有弹窗显示权限不足并自动跳转至登录页面

(2) 文章摘要在没有一或二级标题会无法生成

posted on 2024-09-14 11:23  沐阳Yo  阅读(56)  评论(0)    收藏  举报