【测试】博客系统的测试报告
项目背景
个人博客系统采用了 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();@BeforeAllstatic 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); // 比对不同}// 注意更改驱动释放位置(在最后一个类/测试用例之后)@AfterAllstatic 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 {
}相关文章:
【测试】博客系统的测试报告
项目背景 个人博客系统采用了 SSM 框架与 Redis 缓存技术的组合 ,为用户提供了一个功能丰富、性能优越的博客平台。 在技术架构上 ,SSM 框架确保了系统的稳定性和可扩展性。Spring 负责管理项目的各种组件 ,Spring MVC 实现了清晰的请求处理…...
PointCLIP: Point Cloud Understanding by CLIP
Abstract 近年来,基于对比视觉语言预训练(CLIP)的零镜头和少镜头学习在二维视觉识别中表现出了令人鼓舞的效果,该方法在开放词汇设置下学习图像与相应文本的匹配。然而,通过大规模二维图像-文本对预训练的CLIP是否可以推广到三维识别&#x…...
搜索(剪枝)
定义: 剪枝,就是减少搜索树的规模、尽早排除搜索树中不必要分支的一种手段。 在深度优先搜索中,有以下几类常见的剪枝方法: 优化搜索顺序排除等效冗余可行性剪枝最优性剪枝记忆化剪枝 例题1:AcWing 167.木棒 题目:…...
python基础知识点
最近系统温习了一遍python基础语法,把自己不熟知的知识点罗列一遍,便于查阅~~ python教程 Python 基础教程 | 菜鸟教程 1、python标识符 以单下划线开头 _foo 的代表不能直接访问的类属性,需通过类提供的接口进行访问,不能用 f…...
Android SurfaceFlinger——GraphicBuffer获取内存信息(三十一)
上一篇文章介绍了 GraphicBuffer 初始化的 initWithSize() 函数中的申请内存流程,这里我们看一下另一个比较重要的函数,GraphicBufferMapper. getTransportSize 获取内存信息。该函数通常在需要了解缓冲区的实际内存占用情况时调用,例如在调试内存使用情况或优化性能时。 一…...
基于 SASL/SCRAM 让 Kafka 实现动态授权认证
一、说明 在大数据处理和分析中 Apache Kafka 已经成为了一个核心组件。然而在生产环境中部署 Kafka 时,安全性是一个必须要考虑的重要因素。SASL(简单认证与安全层)和 SCRAM(基于密码的认证机制的盐化挑战响应认证机制ÿ…...
通用多级缓件组件
背景 业界第三方缓存框架一般为redis,本地缓地ehcache或guava,一般通过spring提供的restTemplate操作缓存 然而这样会存在以下问题: 与缓存中间件强耦合需手动整合多级缓存不支持注解数据更新时无法自动刷新缓存存在缓存穿透、缓存击穿、缓…...
MindIE Service服务化集成部署通义千问Qwen模型
一、昇腾开发者平台申请镜像 登录Ascend官网昇腾社区-官网丨昇腾万里 让智能无所不及 二、登录并下载mindie镜像 #登录docker login -u XXX#密码XXX#下载镜像docker pull XXX 三、下载Qwen的镜像 使用wget命令下载Qwen1.5-0.5B-Chat镜像,放在/mnt/Qwen/Qwen1.5-…...
chrome 接口请求等待时间(installed 已停止)过长问题定位
参考: 解决实际项目中stalled时间过久的问题 背景: 测试反馈系统开 6 个标签页后, 反应变的很慢 定位: 看接口请求瀑布流, 已停止时间很长, 后端返回速度很快, 确定是前端的问题 推测是并发请求窗口数量的问题, 屏蔽部分一直 pending 的接口, 发现速度正常了, 搜到上面的参…...
HDialog特殊动画效果
基于HDialog的特殊动画效果实现 业务场景 在开发过程中直接使用HDialog所展现的效果很快,同时不能够与用户所点击位置进行交互,会造成用户的体验观感不够好。因此需要实现一种能够从用户点击按钮位置以可变动画效果所展现的Dialog效果。 工作原理及实…...
基因组挖掘指导天然药物分子的发现-文献精读34
基因组挖掘指导天然药物分子的发现 摘要 天然产物是临床药物的主要来源,也是新药研发过程中先导化合物结构设计和优化的灵感源泉。但传统策略天然药源分子的发现却遭遇了瓶颈,新颖天然产物的数量逐渐无法满足现代药物开发的需求和应对全球多药耐药的威胁…...
hcip学习 DHCP中继
DHCP 中继 在可能收到 DHCP Discover 报文的接口配置 DHCP 中继, 指明 DHCP 服务器的地址,然后将 DHCP 发现报文以单播的形式送到 DHCP 服务器上 DHCP 中继报文的源地址和目标地址怎么确定 1、源地址:收到 Discover 报文的接口地址 2、目…...
[Mysql-函数、索引]
目录 函数: 日期函数 字符串函数 数学函数 聚合函数 索引: 索引分类 慢查询 创建索引 函数: MySQL函数,是一种控制流程函数,属于数据库用语言。 MySQL常见的函数有: 数学函数 用作常规的数学运…...
org.eclipse.jgit 简单总结
org.eclipse.jgit 是一个用于处理 Git 版本控制系统的纯 Java 库。它允许你读取和写入 Git 仓库,执行如克隆、拉取、推送、提交等操作。下面我将通过几个例子来展示如何使用 org.eclipse.jgit 进行一些常见的 Git 操作。 1. 克隆仓库 克隆一个远程 Git 仓库到本地目…...
Fork软件笔记:一键拉取仓库所有模块
Fork是一个好用的git工具,只是没有中文而已(不过不用翻译也能看使用)。 工具下载地址:https://fork.dev/ 界面展示: 当项目中仓库模块比较多时,可以看到每个模块都是一个分页,每一个都要手动切换…...
常见的锂电保护芯片 单节锂电保护/双节锂电保护芯片
目前外出贸易的要求不断增多,出口的产品基本上都需要带上锂电保护芯片 以下是常见的单节锂电保护芯片的选型 包括了市面上大部分的可用型号。 锂电保护芯片的脚位上面基本都是通用,可以直接替代 双节的锂电保护使用情况较少,需要外置MOS管调节…...
初识Java(六)
一、String类 1、类中有操作字符串的方法 查找:找到某个字符是字符串内的第几个:charAt;找到某个字符在字符串内第一次出现的下标:index 替换:替换所有:replaceAll;替换首个:repla…...
Spring-原理篇-DispatcherServlet 初始化 怎么和IOC进行了打通?
委托模式的体现,在初始化醒目的时候Spring MVC为我们提供了一个DispatcherServlet,映射了所有的路径,所有的请求都会先到达这里然后被转发到具体的Controller 进行处理,此文来探索一下,DispatcherServlet 初始化的时候…...
关于swift- OC混编使用Pod遇到的2个错误
错误1 Cannot find interface declaration for UITableViewCell, superclass of "DEFUITalbleViewCell" Cannot find interface declaration for UIView, superclass of "DefUIView" Cannot find interface declaration for 系统类, superclass of "自…...
Golang | Leetcode Golang题解之第290题单词规律
题目: 题解: func wordPattern(pattern string, s string) bool {word2ch : map[string]byte{}ch2word : map[byte]string{}words : strings.Split(s, " ")if len(pattern) ! len(words) {return false}for i, word : range words {ch : patt…...
FFXIV国际服汉化终极指南:三步实现中文界面完美体验
FFXIV国际服汉化终极指南:三步实现中文界面完美体验 【免费下载链接】FFXIVChnTextPatch 项目地址: https://gitcode.com/gh_mirrors/ff/FFXIVChnTextPatch 还在为《最终幻想XIV》国际服的英文界面而烦恼吗?想要享受国际服丰富内容却苦于语言障碍…...
如何用Playnite打造你的终极游戏库:统一管理Steam、Epic、GOG等20+平台游戏
如何用Playnite打造你的终极游戏库:统一管理Steam、Epic、GOG等20平台游戏 【免费下载链接】Playnite Video game library manager with support for wide range of 3rd party libraries and game emulation support, providing one unified interface for your gam…...
【流体】基于matlab二维稳态不可压缩层流通道流利用FVM和SIMPLE 解平行板间层流的速度、压力和温度【含Matlab源码 15558期】
💥💥💥💥💥💥💞💞💞💞💞💞💞💞欢迎来到海神之光博客之家💞💞💞Ὁ…...
终极指南:如何用BepInEx配置管理器轻松掌控所有游戏模组设置
终极指南:如何用BepInEx配置管理器轻松掌控所有游戏模组设置 【免费下载链接】BepInEx.ConfigurationManager Plugin configuration manager for BepInEx 项目地址: https://gitcode.com/gh_mirrors/be/BepInEx.ConfigurationManager 你是否厌倦了在游戏模组…...
麻雀AI助手Akagi:免费实时分析工具,5分钟提升雀魂游戏水平 [特殊字符]️
麻雀AI助手Akagi:免费实时分析工具,5分钟提升雀魂游戏水平 🀄️ 【免费下载链接】Akagi 支持雀魂、天鳳、麻雀一番街、天月麻將,能夠使用自定義的AI模型實時分析對局並給出建議,內建Mortal AI作為示例。 Supports Majs…...
CharacterAI Python API终极指南:如何快速构建AI对话机器人
CharacterAI Python API终极指南:如何快速构建AI对话机器人 【免费下载链接】CharacterAI Unofficial Python API for character.ai 项目地址: https://gitcode.com/gh_mirrors/ch/CharacterAI 你是否想在自己的Python应用中集成CharacterAI的强大对话功能&a…...
Vue-Tree-List:轻松构建优雅树形结构的Vue组件指南
Vue-Tree-List:轻松构建优雅树形结构的Vue组件指南 【免费下载链接】vue-tree-list 🌲A vue component for tree structure 项目地址: https://gitcode.com/gh_mirrors/vu/vue-tree-list 你是否曾为在Vue项目中实现复杂的树形结构而感到头疼&…...
二维紧束缚模型与量子电路映射技术详解
1. 二维紧束缚模型基础理论 紧束缚模型(Tight-Binding Model)是描述电子在周期性晶体场中运动行为的核心理论框架。这个模型的基本物理图像是:电子大部分时间被束缚在原子核附近,只有少量时间会隧穿到相邻原子轨道。在二维系统中&…...
如何在5分钟内实现游戏手柄控制PC:Gopher360终极指南
如何在5分钟内实现游戏手柄控制PC:Gopher360终极指南 【免费下载链接】Gopher360 Gopher360 is a free zero-config app that instantly turns your Xbox 360, Xbox One, or even DualShock controller into a mouse and keyboard. Just download, run, and relax. …...
一部95分钟AI电影杀进戛纳后,影视行业开始不淡定了
作者:王聪彬今年戛纳电影节的C位,不是红毯,不是明星,也不是哪位导演的新片,AI把C位抢了。8支由火山引擎视频生成大模型Seedance 2.0创作的AI影片,第一次正式登上戛纳舞台。过去代表全球电影工业最高门槛的戛…...
