【测试】博客系统的测试报告

news2024/12/25 0:44:21

项目背景

个人博客系统采用了 SSM 框架与 Redis 缓存技术的组合 ,为用户提供了一个功能丰富、性能优越的博客平台。
在技术架构上 ,SSM 框架确保了系统的稳定性和可扩展性。Spring 负责管理项目的各种组件 ,Spring MVC 实现了清晰的请求处理 和视图渲染 , MyBatis 则高效地处理数据库操作。功能方面 ,用户可以轻松撰写、编辑和发布博客文章。
前端主要有 登录/注册、个人中心、操作博客的相关界面构成。

后端主要有 登录/注册、用户信息操作、博客等相关操作。


项目功能

  • 注册功能:新用户需要填写用户名和密码,验证通过后需要把用户名和加密的密码存入数据库。
  • 个人中心:注册/登录之后跳转到该页面,这个页面可以添加邮箱/Gitee/修改头像。同时还可以跳转到个人博客列表,或者博客广场。
    • 添加邮箱:填入绑定的邮箱号之后,会收到一条验证码。当验证码通过后,就会绑定邮箱。同时把绑定的邮箱信息存入数据库。
    • 修改邮箱:同添加邮箱。
    • 添加Gitee:选择自己的Gitee链接,提交完成后会存入数据库。点击Gitee会跳转到个人首页。
    • 修改Gitee:同添加Gitee。
    • 我的博客:点击会跳到个人博客列表页。
    • 博客广场:点击会跳到博客广场。
  • 我的博客:只会显示自己写的博客。博客按照发布时间升序排列。只显示每篇博客的标题,发布时间,文章的前一部分的内容。可以通过查看全文查看整篇文章。可以通过修改来修改文章的内容。通过删除来删除选中的文章。
  • 博客广场:与我的博客列表相似,只不过这里是全部人的博客。另外只有查看全文的显示。
  • 写博客:当登录之后,就可以点击写博客进行博客的书写和发布。
  • 注销:当登陆后可以点击注销进行退出。

测试

功能测试

用户

注册

登录

注销

头像

邮箱

Gitee

博客

个人广场

博客广场

查看博客

增加博客

修改博客

删除博客

自动化测试

引入依赖

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

        <!--        添加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>

创建公共类

import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;

public class AutoTestUtils {
    // 为了降低代码冗余度,直接在这里实现代码的复用
    public static ChromeDriver driver;

    // 创建驱动对象
    public static ChromeDriver createDriver() {
        // 无头模式
        ChromeOptions options = new ChromeOptions();
        options.addArguments("-headless");

        // 判断驱动对象是否已经创建
        if(driver == null) {
            // 无头模式
            driver = new ChromeDriver(options);

            // 默认的有头模式
//            driver = new ChromeDriver();
            // 创建隐式等待,确保页面渲染出来
            driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(6));
        }
        return driver;
    }

    /*
    * 保存现场<截图>
    * 把所有用例的执行结果进行保存
    * 注意:保存的屏幕截图的名字应该是动态生成的,否则会进行图片的覆盖
     */
    // 获取动态文件名
    public List<String> getTime() {
        SimpleDateFormat sim1 = new SimpleDateFormat("yyyyMMdd-HHmmssSS");
        String fileName = sim1.format(System.currentTimeMillis());
        // 希望文件按天的维度进行文件夹的分类保存
        SimpleDateFormat sim2 = new SimpleDateFormat("yyyyMMdd");
        String dirName = sim2.format(System.currentTimeMillis()); // 文件夹的名字
        // 使用链表进行保存
        List<String> list = new ArrayList<>();
        list.add(dirName);
        list.add(fileName);
        return list;

    }

    // 为了区分是哪个用例返回的,可以加上用例的名称进行保存
    public void getScreenShot(String str) throws IOException {
        List<String> list = getTime();
        // 文件保存路径:dirName+fileName
        // ./指的是当前路径,这里来说就是BlogAutoTest目录下
        // 如果目前期望的路径:./src/test/java/com/blogWebAutoTest/dirName/fileName
        // 注意图片保存的路径以及名称!
        String fileName = "./src/test/java/com/blogWebAutoTest/"
                + list.get(0) + "/" + str + "_" + list.get(1) + ".png"; // 保存的路径+名称
        File scrFile = driver.getScreenshotAs(OutputType.FILE); // 获取到的屏幕截图
        // 把屏幕截图生成的文件放到指定路径下
        FileUtils.copyFile(scrFile,new File(fileName));
    }
}

具体测试

测试详情页

import com.blogWebAutoTest.common.AutoTestUtils;
import org.junit.jupiter.api.*;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;

import java.io.IOException;
import java.time.Duration;

// 博客详情页测试
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BlogDetailTest extends AutoTestUtils {
    public static ChromeDriver driver = createDriver();
    @BeforeAll
    static void baseControl() {
        driver.get("http://127.0.0.1:8370/myblog_list.html");
    }

    /*
    * 详情页打开正确,但是因为没有blogId会出现Undefined
    */
    @Test
    @Order(1)
    void undefindedTest() throws IOException {
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));
        String expect = "";
        String fact = driver.findElement(By.xpath("/html/body/div[2]/div[2]/div/div[1]")).getText();
        getScreenShot(getClass().getName());
        Assertions.assertEquals(expect,fact);
    }

    /*
    * 测试详情页正确打开[有blogId]
    * 测试标题以及时间(必定有)
    * 这里其实还有一种情况:不存在blogId
    */
    @Test
    @Order(2)
    void blogDetailPageRight() throws IOException {
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));
        driver.get("http://127.0.0.1:8370/blog_content.html?id=9");
        driver.findElement(By.cssSelector("body > div.container > div.container-right > div > h3"));
        driver.findElement(By.cssSelector("body > div.container > div.container-right > div > div.date"));
        driver.findElement(By.xpath("//*[@id=\"content\"]/p"));
        getScreenShot(getClass().getName());
        driver.findElement(By.xpath("/html/body/div[1]/a[1]")).click(); // 回到列表页
    }

    /*
    * 测试“删除”按钮
    * 删除后会跳回到列表页,然后与最上面的时间进行比对即可【不比较标题,因为标题可能为空】
    * 这里是要删除第一篇博客
    */
    @Test
    @Order(3)
    void deleteTest() throws IOException {
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));
        getScreenShot(getClass().getName());
        driver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > a")).click();
        String before = driver.findElement(By.xpath("/html/body/div[2]/div[2]/div/div[1]")).getText();
        driver.findElement(By.cssSelector("#delete_button")).click();
        String after = driver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > div.date")).getText();
        getScreenShot(getClass().getName());
        Assertions.assertNotEquals(before,after);  // 比对不同
    }

    // 注意更改驱动释放位置(在最后一个类/测试用例之后)
    @AfterAll
    static void driverQuite() {
        driver.quit();
    }
}

其他界面也是类似。

最后一起跑一下。

import org.junit.platform.suite.api.SelectClasses;
import org.junit.platform.suite.api.SelectPackages;
import org.junit.platform.suite.api.Suite;

// 测试套件运行
@Suite
@SelectClasses({BlogLoginTest.class, BlogListTest.class,BlogEditTest.class,BlogDetailTest.class,DriverQuiteTest.class})
public class runSuite {
}

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

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

相关文章

【Linux系统】POSIX信号量 线程池

PISIX信号量 概念 POSIX信号量和SystemV信号量作用相同&#xff0c;都是用于同步操作&#xff0c;达到无冲突的访问共享资源目的。 但POSIX可以用于线程间同步。 引入环形队列的概念 环形队列&#xff1a;当队列为空||为满时 head end&#xff0c;我们发现这样无法区分为空…

Springboot2.6.13整合flowable6.8.1

背景 项目上需要使用到工作流相关内容&#xff0c;比对了好久采用flowable实现&#xff0c;该插件和activiti等很相似&#xff0c;基本上可以直接移植 代码如下 <!-- 父引用用--><parent><groupId>org.springframework.boot</groupId><artifactI…

LLM的训练与推断

LLM的训练与推断 目前比较流行的大模型一般都是自回归模型。在推理时&#xff0c;它类似于RNN&#xff0c;每次计算下一个token的概率。也就是说&#xff0c;如果除去最开始的输入情况下&#xff0c;最终推理长度为n的话&#xff0c;就需要计算n次。但是训练却是并行化的。 在…

你想活出怎样的人生?我只活一次,所以想做自己

你好&#xff0c;我是腾阳。 在这纷繁复杂的世界中&#xff0c;我们每个人都像是一颗颗星星&#xff0c;闪烁着自己的光芒。 然而&#xff0c;在这光芒背后&#xff0c;有多少人真正了解自己&#xff0c;又有多少人敢于追随内心的声音&#xff0c;去追寻那些看似遥不可及的梦…

arduino程序-程序函数2(led电路及相关函数)(基础知识)

arduino程序-程序函数2&#xff08;led电路及相关函数&#xff09;&#xff08;基础知识&#xff09; 1-9 程序函数2&#xff08;led电路及相关函数&#xff09;点亮LED需要Blink程序PinMode(LED_BUTTIN,OUTPUT)DigitalWrite(LED_BUILTIN,HIGH)第一个参数(13/LED_BUILTIN)第二个…

由浅入深的了解进程(1)

进程 1、冯诺依曼体系结构(硬件)2、操作系统(软件)2、1、概念2、2、结构示意图(简略版)3、3、尝试理解操作系统 1、冯诺依曼体系结构(硬件) 大多数常见的计算机&#xff0c;类似笔记本或者是台式电脑&#xff0c;包括不常见的计算机&#xff0c;类似服务器&#xff0c;大多遵循…

安装python插件命令集合

安装python插件pyecharts库 pip install pyecharts -i https://pypi.tuna.tsinghua.edu.cn/simple 安装python插件pandas库 pip install pandas -i https://pypi.tuna.tsinghua.edu.cn/simple PyCharm 中安装步骤&#xff1a;

Linux安装TrueNAS(网络附加存储)教程 –第1部分

TrueNAS CORE&#xff08;原名FreeNAS&#xff09;是一款流行的存储系统&#xff0c;可帮助您构建自己的高质量存储设置&#xff0c;而无需支付软件费用。您可以将其安装在计算机硬件或虚拟机 (VM) 上&#xff0c;以获得开源存储的好处。 您可以在家中、办公室或数据中心使用T…

微信小程序云开发订单微信支付与小票和标签打印的完整高效流程

一个字“全”&#xff01;&#xff01;&#xff01; 前言一、流程设定1、如何开通云支付流程2、以订单下单为例的支付流程2.1 业务场景介绍2.2 业务场景流程图 二、代码与代码文件组成1、页面JS2、云函数payPre3、支付回调函数pay_cb3.1 准备条件3.2 必要认知3.3 pay_cb 完整函…

day03 3.文件IO 4.文件属性函数

作业 1> 使用文件IO完成&#xff0c;将源文件中的所有内容进行加密&#xff08;大写转小写、小写转大写&#xff09;后写入目标文件中 源文件内容不变 #include <myhead.h>int main(int argc, const char *argv[]) {if(argc ! 3) //判断打开的文件个数{printf(&quo…

【Python学习手册(第四版)】学习笔记10-语句编写的通用规则

个人总结难免疏漏&#xff0c;请多包涵。更多内容请查看原文。本文以及学习笔记系列仅用于个人学习、研究交流。 本文较简单&#xff0c;5-10分钟即可阅读完成。介绍Python基本过程语句并讨论整体语法模型通用规则&#xff08;冒号、省略、终止、缩进、其他特殊情况&#xff0…

JavaFX布局-StackPane

JavaFX布局-StackPane 常用属性alignmentpadding 实现方式Java实现fxml实现 所有子节点堆叠在一起&#xff0c;通常最后一个添加的子节点会显示在最上面 常用属性 alignment 对齐方式 stackPane.setAlignment(Pos.CENTER_RIGHT); public enum Pos {/*** Represents positioni…

LeYOLO,一种用于目标检测的新型可扩展且高效的CNN架构

摘要 在目标检测中&#xff0c;深度神经网络的计算效率至关重要&#xff0c;尤其是随着新型模型越来越注重速度而非有效计算量&#xff08;FLOP&#xff09;。这一发展趋势在某种程度上忽视了嵌入式和面向移动设备的AI目标检测应用。在本文中&#xff0c;我们基于FLOP关注于高…

马斯克的Memphis AI超级计算中心:全球最强AI训练集群的诞生

引言 近期&#xff0c;马斯克宣布其最新的Memphis AI超级计算中心正式启动&#xff0c;这一新闻引发了科技界的广泛关注。该中心配备了10万块液冷H100 GPU&#xff0c;成为全球最强大的AI训练集群。本文将深入探讨Memphis AI超级计算中心的建设过程、技术细节、以及其对未来人…

Unity多客户端位置同步信息

书接上文&#xff0c;有了一个基本的网络同步消息的服务器&#xff0c;客户端这边其实要做的工作就简单许多。 如果对位置信息的保密程度没那么高的话&#xff0c;可以放在客户端处理这部分的逻辑。 即一个客户端移动的时候&#xff0c;另一个客户端跟着移动&#xff0c;基本…

在Java中利用GeoHash实现高效的‘附近xxx‘功能

GeoHash的介绍 GeoHash是一种高效的地理编码系统&#xff0c;它通过将地球表面划分为网格并用字母数字组合的字符串来表示每个区域。 这种编码方法将二维的经纬度坐标转换为一维的字符串&#xff0c;使得地理位置的存储和检索变得更加简单。GeoHash的核心原理是将经纬度坐标转…

后端开发工程师vue2初识的学习

博客主页&#xff1a;音符犹如代码系列专栏&#xff1a;JavaWeb关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 什么是Vue&#xff1f; Vue &#xff08;通常指 Vue.js&#xff09;是一个用…

权限管理的概述以及vue开发前端的路由、菜单、按钮权限控制实现方案

1. 权限管理概念 1.1 权限定义 权限管理是确保用户只能访问被授权资源的机制。在计算机系统中&#xff0c;权限通常指对特定数据或功能的访问权。权限的设置和控制对于保护数据安全和系统安全至关重要。 1.2 前端权限控制重要性 前端权限控制是用户与应用交互的第一道防线。…

超级好用的免费在线流程图软件

超级好用的免费在线流程图软件 Draw io 是一款免费开源的流程图绘制工具&#xff0c;可在浏览器中使用或下载安装。它提供了简单易用的界面和丰富的图形元素&#xff0c;支持创建各种类型的流程图、组织结构图、网络图等。Draw io 支持导入和导出多种格式&#xff0c;包括 PDF…

从零开始,快速打造API:揭秘 Python 库toapi的神奇力量

在开发过程中&#xff0c;我们常常需要从不同的网站获取数据&#xff0c;有时候还需要将这些数据转化成API接口提供给前端使用。传统的方法可能需要大量的时间和精力去编写代码。但今天我要介绍一个神奇的Python库——toapi&#xff0c;它可以让你在几分钟内创建API接口&#x…