博客测试报告

目录

一.项目简介

1.1项目概述

1.2测试目的

1.3测试范围

二.测试环境

2.1开发环境

2.2测试工具

三.功能展示 

四.自动化功能测试

4.1测试准备阶段

4.2博客注册-登陆测试

4.3博客列表测试

4.4个人中心测试

4.5博客发表测试

4.6自动化集成

4.7自动化测试总结


一.项目简介

1.1项目概述

        本项目名为知识殿堂,Web网站程序,采取了前后端分离的方法实现,使用MYSQL数据库存储用户数据以及文章数据,同时结合Redis记录当前的Seesion会话。 

 本项目的前端页面由八个页面构成:登陆页面、注册页面、公共博文列表、搜索页面、列表页面、个人中心页面、文章发表页面以及文章详情页面。                                                                    后端实现的功能有:验证码生成、用户登陆、退出登陆、修改密码、强制登陆、发表(修改、删除)文章,文章搜索,上传头像、修改个人信息等功能。

1.2测试目的

        本次测试的目的主要在于以下几个方面:

  1. 功能验证: 测试用于验证个人博客的基本功能是否按预期工作。这包括用户能否正确注册、登录、发布文章、搜索功能,修改个人信息等核心功能。通过Selenium 等自动化测试工具可以确保这些功能的正确性和稳定性。

  2. 性能评估: 测试可以用于评估个人博客在不同负载条件下的性能表现。通过压力测试和性能测试,可以确定博客系统在同时处理多少用户、同时发布文章或评论时的响应时间和资源消耗情况。这有助于优化系统,确保其在高负载下依然能够保持稳定性和响应速度。

  3. 安全性检查: 测试用于评估个人博客的安全性。这包括检查用户认证和授权机制是否正确实现,以防止未授权访问和数据泄露。此外,还可以通过安全测试评估系统是否容易受到常见的安全攻击,如密码破解、文章等。

1.3测试范围

  1. 单元测试:针对代码中最小的可测试单元(如函数、方法)进行的测试。在个人博客项目中,可以编写单元测试来验证各个模块、服务、控制器等的功能是否按预期工作。例如,验证用户注册、登录逻辑的正确性,文章发布、获取文章列表等功能的各个边界条件和异常情况的处理。
  2. 集成测试: 集成测试是测试不同模块之间的集成,以验证它们在一起工作时是否如预期。在个人博客项目中,集成测试可以确保整个系统的各个组件(如数据库、服务、API等)在协同工作时没有问题。例如,测试用户管理模块与文章发布模块之间的集成,确保用户发布文章时能够正确保存到数据库并展示在博客页面上。

  3. 功能测试: 功能测试是测试整个功能或者用户场景的测试,以验证系统是否能够按照用户需求正常工作。在个人博客项目中,功能测试可以覆盖用户注册登录流程、文章发布与编辑流程、评论管理、用户权限管理等核心功能。这些测试通常模拟用户的实际操作,检查系统是否能够正确响应和处理用户的各种输入和操作。

二.测试环境

2.1开发环境

        开发工具:jdk8.0版本IntelliJ IDEA、linux云服务器

        本项目的开发技术栈:SpringBoot2.0+MySQL数据库5.8+MyBatis-Plus+Redis

SpringBoot技术:开源的Java框架,用于快速构建基于Spring的应用程序。它简化了Spring应用的配置和部署,提供了各种开箱即用的功能,如自动配置、内嵌服务器等。

MySql数据库:关系型数据库管理系统,广泛用于Web应用程序的数据存储。它支持标准的SQL语法,具有良好的性能和稳定性,能够处理大量数据和复杂的查询。

MyBatis-Plus:MyBatis 的增强工具包,封装了通用的 CRUD 操作(增删改查),通过继承 BaseMapper 接口或者使用 IService 接口的默认实现,可以直接使用基础的 CRUD 方法,无需编写 XML 映射文件。

Redis:高性能的开源键值对存储数据库,广泛用于缓存、会话管理、消息队列等场景。它支持丰富的数据结构(如字符串、哈希、列表、集合等),并提供了各种操作这些数据结构的API。

2.2测试工具

        测试工具:selenium、Loadrunner、JUnit、Postman工具

  1. Selenium

    • 用途:主要用于自动化Web应用程序的测试。
    • 特点:支持多种浏览器和操作系统,可以模拟用户在浏览器中的操作,如点击、输入文本等,适合于功能测试和回归测试。
  2. Loadrunner

    • 用途:用于进行性能测试,可以模拟多种用户同时访问系统,评估系统的负载能力和性能表现。
    • 特点:支持多种协议(如HTTP、HTTPS、Web Services等),能够生成大量的虚拟用户,通过监控和分析来识别系统的瓶颈和性能问题。
  3. JUnit

    • 用途:是一个Java编程语言的单元测试框架,用于编写和运行重复测试。
    • 特点:提供了断言功能和测试运行器,可以方便地组织和执行单元测试,是Java开发中常用的测试工具之一。
  4. Postman

    • 用途:主要用于API测试和开发的工具,支持发送HTTP请求并查看响应。
    • 特点:提供了友好的用户界面,可以创建和组织请求集合,支持环境变量和脚本编写,方便进行接口测试、自动化测试和性能测试的初步验证。
  5. Fiddler:网络调试工具,主要用于捕获、检查和修改 HTTP 流量。

三.功能展示 

1.登陆-注册功能

        由于我添加了验证码验证码,无法提出图片中的数字,因此我登陆页面我将无法自动化测试(技术不足的原因)。

        注册功能,输入用户名和密码,会随机生成用户ID(唯一),以用户ID和密码才能登陆。

2.博客列表

        如上图,登陆之后的页面当中,是存在搜索功能的,也可以查看文章和写博客的能力。而未登陆,只有一个列表,且无法查看。

3.个人中心

个人中心如上图,内部可以修改个人信息,密码,还有点击头像可以更换。

4.发布文章

可以选择指定的类型进行发表。

5.查看文章

如图,文章详情列表当中含有发布时间,以及访问量!

四.自动化功能测试

如上图,我们需要进行测试的模块。

4.1测试准备阶段

        新建立一个Maven项目,引入依赖(selenium4、junit5等):


<!--        添加selenium依赖-->
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>4.0.0</version>
        </dependency>
 
 
        <!--        添加junit5依赖-->
        <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>

创建驱动和释放类

        创建一个驱动类,负责运行自动化Web应用程序,可继续接下来的操作:模拟用户在浏览器中的操作。同时我们将释放驱动也添加在同一个类当中。并设置驱动对象为静态的,就可以让创建和销毁驱动的步骤执行一次,其他类如果需要驱动直接继承该类。

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;

public class Init {
   private ChromeOptions options;
    private WebDriver driver;
    private Chrome chrome ;

    @BeforeAll
    static void SetUp() {
       chrome = new Chrome();
        options = new ChromeOptions();
        options.setBinary("D:\\Chrome\\chrome.exe");
        options.addArguments("--remote-allow-origins=*");
        driver = new ChromeDriver(options);
    }
    @AfterAll
    static void TearDown() {
       driver.quit();
    }
}

创建CSV文件操作类

public class CSVFileReader {
    private static final String CSV_FILE_NAME = "User.csv";
    private static long nextId = 1;

    //读取资源
    public List<User> readCSVFile() {
        List<User> t1= new ArrayList<>();
        try {
            // 加载 CSV 文件资源
            ClassPathResource resource = new ClassPathResource("User.csv");

            // 获取文件的输入流
            InputStream inputStream = resource.getInputStream();

            // 使用 BufferedReader 逐行读取文件
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
                String line;
                boolean headerLine = true; // 标记是否为首行(表头)
                while ((line = reader.readLine()) != null) {
                    if (headerLine) {
                        headerLine = false;
                        continue; // 跳过表头行
                    }

                    // 分割 CSV 行数据
                    String[] fields = line.split(",");

                    // 解析数据
                    if (fields.length >= 3) {
                        String id = fields[0].trim();
                        String username = fields[1].trim();
                        String password = fields[2].trim();
                        // 创建 Person 对象并添加到列表中
                        // 获取当前行的 ID 最大值
                        long currentId = Long.parseLong(id);
                        if (currentId >= nextId) {
                            nextId = currentId + 1; // 更新下一个可用的 ID
                        }
                        User user = new User(username,password);
                        t1.add(user);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return t1;
    }
    //写入资源
    public void writerCSVFile(String username,String password) throws IOException {
        ClassPathResource resource = new ClassPathResource(CSV_FILE_NAME);
        File file = resource.getFile();
        // 追加新数据到 CSV 文件
        FileWriter writer = new FileWriter(file, true);
        try (BufferedWriter bw = new BufferedWriter(writer)) {
            long id = nextId++;
            // 组装新数据行
            String csvLine = String.format("%d,%s,%s\n", id, username, password);
            // 写入到文件
            bw.write(csvLine);
        }
    }
}

注:可能之后的你的保存路径和我不一样! 

4.2博客注册-登陆测试

  1. 创建博客注册登陆测试类(Blog_LoginReg)继承Init类,获得驱动。
  2. 创建注册方法,将注册好的用户信息,通过element组件的方式保存在csv文件里。
  3. 创建登陆方法,将csv当中的信息作为传递值,看看是否可以传递
  4. 类上使用@TestMethodOrder(MethodOrderer.OrderAnnotation.class)注解,然后通过@Order注解设定运行顺序,一次性运行,判断是否出错。

注册测试方法:

     @Order(1)
     @Test
    void RegSuccess() throws IOException, InterruptedException {
        for(int i=0; i < 10;i++){
            driver.get("http://127.0.0.1:8080/reg.html");
            Random random = new Random();
            String password = new String();
            for(int k =0;k < 10;k++){
                int n = random.nextInt(10);
                password = password + n;
            }
            String username = "tq"+random.nextInt(100);
            driver.findElement(By.cssSelector("#username")).sendKeys(username);
            driver.findElement(By.cssSelector("#password1")).sendKeys(password);
            driver.findElement(By.cssSelector("#password2")).sendKeys(password);
            sleep(3000);
            driver.findElement(By.cssSelector("#submit")).click();
            //注册的数据保存在csv当中
            csvFileReader.writerCSVFile(username,password);
        }
    }

        会自动创建十个账户和密码,然后保存在自定义的csv文件当中,便于我们之后的登陆测试!

登陆测试

  @Order(2)
    @Test
    void LoginSuccess() throws InterruptedException {
        List<User> t1 = csvFileReader.readCSVFile();
        for(User user : t1){
            driver.get("http://127.0.0.1:8080/login.html");
            driver.findElement(By.cssSelector("#username")).sendKeys(user.getName().trim());
            driver.findElement(By.cssSelector("#password")).sendKeys(user.getPassword().trim());
            driver.findElement(By.cssSelector("#submit")).click();
            sleep(3000);
        }
    }

        使用保存在csv文件里的数据,用于登陆测试,操作成功!

4.3博客列表测试

        当列表中文章数目为0时,通过断言判断,从而停止;若不为0,则获取所有“ 查看文章” 的按钮,然后使用方法click()点击,再使用方法.navigate().back()返回到上一级目录,重复进行!

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class Blog_List extends Init {
    CSVFileReader csvFileReader = new CSVFileReader();
    @Order(1)
    @Test
    void ListSuccess() {
        driver.get("http://127.0.0.1:8080/login.html");
        int size = driver.findElements(By.cssSelector(".title")).size();
        //如果为空,则断言不通过,文章数为0
        Assertions.assertNotEquals(0, size);
        List<WebElement> detailLinks = driver.findElements(By.cssSelector("a.detail"));
        for (WebElement link : detailLinks) {
            link.click();
            driver.navigate().back();
        }
    }
}

4.4个人中心测试

        个人中心测试:登陆-->主页-->我的,然后开始测试:1.查看、编辑和删除自己的文章。2.点击头像,更换!3.点击个人设置,然后修改密码+修改个人信息

1.查看、编辑和删除自己的文章。通过断言,判断是否成功!

@Order(2)
    @Test
    void articleSuccess() {
        //查看文章
        List<WebElement> detailLinks = driver.findElements(By.cssSelector("#createDiv > div:nth-child(n) > div.san > a:nth-child(1)"));
        for (WebElement link : detailLinks) {
            link.click();
            driver.navigate().back();
        }
        //修改文章
        List<WebElement> updateLinks = driver.findElements(By.cssSelector("#createDiv > div:nth-child(n) > div.san > a:nth-child(2)"));
        for (WebElement link : detailLinks) {
            link.click();
            WebElement element = driver.findElement(By.cssSelector("#title"));
            //将每一篇标题的末尾添加tq02
            element.sendKeys(element.getAttribute("value")+"tq02");
            driver.findElement(By.xpath("/html/body/div[2]/div[1]/button")).click();
            driver.switchTo().alert().accept();
        }
        List<WebElement> SelectLinks = driver.findElements(By.cssSelector("#createDiv > div:nth-child(n) > div.san > a:nth-child(1)"));
        for (WebElement link : detailLinks) {
            link.click();
            //判断是否添加了"tq02"
            Assertions.assertTrue(driver.findElement(By.cssSelector("#title")).getText().endsWith("tq02"));;
            driver.navigate().back();
        }
        //删除文章
        String str = driver.findElement(By.cssSelector("#createDiv > div:nth-child(1) > div.title")).getText();
        driver.findElement(By.cssSelector("#createDiv > div:nth-child(1) > div.san > a:nth-child(3)")).click();
        // 进行断言
        Assertions.assertNotEquals(driver.findElement(By.cssSelector("#createDiv > div:nth-child(1) > div.title")).getText(), str, "元素内容不符合预期");
    }

2..点击头像,更换!

 @Order(1)
    @Test
    void PhotoSuccess() {
        driver.findElement(By.cssSelector("body > div.nav > a:nth-child(5)"));
        //点击头像
        driver.findElement(By.cssSelector("#photo"));
        //点击更换头像
        driver.findElement(By.cssSelector("#myDialog2 > div > div > button:nth-child(1)"));
        //上传头像
        WebElement uploadInput =driver.findElement(By.xpath("//*[@id=\"photo1\"]"));
        uploadInput.sendKeys("//本地照片路径");
        driver.findElement(By.cssSelector("#myDialog2 > div > div > button:nth-child(2)"));
    }

3.个人信息修改

 @Order(3)
    @Test
    void InfoSuccess() throws InterruptedException {
        //修改密码
        driver.findElement(By.cssSelector("body > div.nav > div > div > div > button:nth-child(1)"));
        driver.findElement(By.cssSelector("#password1")).sendKeys("12345");
        driver.findElement(By.cssSelector("#password2")).sendKeys("54321");
        driver.findElement(By.cssSelector("#password3")).sendKeys("54321");
        driver.findElement(By.cssSelector("#myDialog > div > div.row1 > button:nth-child(1)")).click();
        //测试是否注销,重新登陆
        driver.findElement(By.cssSelector("body > div.nav > div > div > div > a")).click();
        Assertions.assertEquals(driver.getCurrentUrl(),"http://127.0.0.1:8080/login.html","未返回登陆页面");
        driver.findElement(By.cssSelector("#username")).sendKeys("tq02");
        driver.findElement(By.cssSelector("#password")).sendKeys("54321");
        driver.findElement(By.cssSelector("#submit")).click();
        //登陆成功之后,修改用户信息
        driver.get("http://127.0.0.1:8080/myblog_list.html");
        driver.findElement(By.cssSelector("body > div.nav > div > div > div > button:nth-child(3)"));
        driver.findElement(By.cssSelector("#username")).sendKeys("TQ01");
        driver.findElement(By.cssSelector("#git")).sendKeys("tq.com");
        driver.findElement(By.cssSelector("#myDialog3 > div > div.row1 > button:nth-child(1)")).click();
        //验证用户名是否更改
        Assertions.assertTrue(driver.findElement(By.cssSelector("#article")).getText().endsWith("tq01"));;
    }

4.5博客发表测试

        在这个界面下分别对打开网页是否正常、测试输入标题和正文博客是否可以正常发布、测试“写博客”按钮是否可以正常使用。

    @Order(1)
    @Test
    public void issuance(){
        driver.findElement(By.cssSelector("body > div.nav > a:nth-child(5)")).click();
        driver.findElement(By.cssSelector("#title")).sendKeys("自动化测试01");
        driver.findElement(By.xpath("//*[@id=\"editorDiv\"]/div[1]/div[6]")).sendKeys("我爱自动化测试啊");
        driver.findElement(By.xpath("//*[@id=\"editorDiv\"]/div[1]/div[6]")).sendKeys("我爱自动化测试啊");
        driver.findElement(By.xpath("//*[@id=\"synopsis\"]")).sendKeys("简介");
        // 找到下拉框元素
        WebElement dropdown = driver.findElement(By.id("@mySelect"));
        // 创建 Select 对象
        Select select = new Select(dropdown);
        select.selectByIndex(1);
        //发布文章
        driver.findElement(By.xpath("/html/body/div[2]/div[1]/button")).click();
        driver.switchTo().alert().dismiss();

        //验证是否发布成功
        Assertions.assertEquals("自动化测试01",driver.findElement(By.xpath("//*[@id=\"createDiv\"]/div[1]/div[1]")).getText(),"标题不一样错误");
        Assertions.assertEquals("简介",driver.findElement(By.xpath("//*[@id=\"createDiv\"]/div[1]/div[3]")).getText(),"简介不一样错误");

    }

4.6自动化集成

        以上便是所有功能自动化测试,但是很明显我将这些功能写在不同的类,甚至不同的包中当中,难道我还得一个一个类进行测试吗?代码岂不是有冗余?因此我们可以使用JUnit 测试套件。配合@RunWith(JUnitPlatform.class)和@SelectClasses({包名.类名.class})

@Suite
@SelectClasses({Blog_loginreg.class,Blog_List.class, Article.class,Article.class})
//若不同包下的测试类同名的情况:
// @SelectClasses({
//   com.example.package1.TestClassA.class,
//   com.example.package2.TestClassA.class
//})
//第二种方法-扫描整个包下的测试类:
@SelectPackages(value={"包名", "包名"})
public class MyTestSuite {
}

4.7自动化测试总结

特点:根据个人项目来设计的测试用例,然后根据测试用例使用selenium4自动化测试工具和junit5单元测试框架结合来实现web自动化测试的(功能、步骤、技术一定要明确)

亮点:

  1. 强大的浏览器控制能力: Selenium 4 提供了更新和改进后的浏览器控制功能,包括支持最新的浏览器版本和更稳定的 WebDriver API。这使得你可以更精确地模拟用户操作和测试各种 web 应用程序。

  2. 异步测试支持: JUnit 5 支持异步测试方法,这与 Selenium 4 的异步特性(如异步执行命令和等待条件)非常契合。这样可以更有效地处理页面加载、AJAX 请求等异步操作,提高测试的效率和可靠性。

  3. 丰富的断言和校验功能: JUnit 5 提供了丰富的断言库,可以用来验证页面元素的状态、属性和行为。结合 Selenium 4 的元素定位和操作功能,可以轻松编写详细而清晰的测试断言,确保应用程序的正确性。

  4. 参数化测试: JUnit 5 支持参数化测试,可以通过不同的参数运行相同的测试方法。这对于测试不同数据集或不同配置的 web 应用程序非常有用,可以通过多次运行相同的测试方法来覆盖更多的场景。

  5. 并发执行: JUnit 5 具有更好的并发执行支持,可以并行运行测试方法,从而缩短整体测试时间。这与 Selenium 4 的多线程执行能力非常匹配,尤其在大型测试套件或需要快速反馈的场景下,能够显著提升效率。

  6. 容易集成和扩展: JUnit 5 设计良好,支持插件和扩展,能够与各种 CI/CD 工具和报告生成工具集成。结合 Selenium 4 的稳定的 API 和丰富的第三方库支持,可以实现高度定制化的自动化测试框架,满足特定需求和复杂场景的测试要求。

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tq02

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值