博客系统测试报告

一、报告描述

1.项目描述

博客系统是一个轻量级内容管理平台,旨在为用户提供简洁、高效的个人写作与分享体验。系统摒弃复杂功能,专注于核心的文章发布、管理与阅读需求。

核心模块如下

  • 用户模块:登录,注销及个人信息管理
  • 文章管理:发布、编辑、删除、查看文章,支持标签分类
  • 内容展示:按时间线 / 标签筛选文章

具体功能:

1.登录功能

填写用户名和密码,点击提交即可登录。

2.退出登录功能

成功登录后,右上角有"注销"按钮,点击即可退出登录。

3.编辑博客功能

成功登录后,右上角有"写博客"按钮,点击即可进入编辑博客页面。

4.发布博客功能

输入博客标题和博客内容后,点击"发布文章"即可发布博客。

5.查看博客功能

发布博客后,点击"查看全文"即可即跳转到博客详情页。

6.重新编辑博客功能

在博客详情页,点击"编辑"即可在原来基础上对博客进行修改。

7.删除博客功能

在博客详情页,点击"删除"即可删除该博客

2.测试目的和范围

测试目的:

  1. 功能验证

    确保系统核心功能按设计正常工作,例如:

    • 用户登录、权限控制流程完整无误
    • 文章发布、编辑、删除、展示等操作符合预期
  2. 性能保障

    验证系统在不同负载下的运行表现,包括:

    • 页面加载速度(尤其文章列表、详情页)
    • 高并发场景下的稳定性(如热门文章访问峰值)
  3. 安全性防护

    排查潜在安全风险,防止常见攻击,例如:

    • 防止未授权访问,用户信息泄露
    • 用户密码加密存储与权限边界校验
    • 敏感操作(如删除文章)的防误触与权限控制
  4. 兼容性确认

    确保系统在不同环境下的一致性,包括:

    • 主流浏览器(Chrome/Edge/Firefox 等)的适配
    • 不同网络环境(弱网 / 正常网络)下的可用性
  5. 用户体验优化

    从用户视角验证操作流程的合理性,例如:

    • 错误提示清晰易懂(如登录失败原因)
    • 操作流程简洁直观(如发布文章的步骤复杂度)
    • 异常场景的容错能力(如网络中断后的数据恢复)

测试范围:

  • 登录界面:验证用户正常以及异常登录是否满足需求
  • 博客首页:验证登录状态下和未登录状态下的元素是否满足需求
  • 博客详情页:验证登录状态下和未登录状态下的元素是否满足需求
  • 博客编辑页:验证登录状态下和未登录状态下的元素以及操作是否满足需求

3.测试方法与策略

测试方法:

  • 界面测试

核对所有界面元素(按钮、输入框、图标、文字等)是否按设计稿完整显示,无遗漏(如 "发布文章" 按钮是否存在、标签栏是否显示完整)。

  • 功能测试

主要采用手工测试结合自动化测试,对博客系统各核心功能模块(用户登录,博客详情,博客编辑,博客发布)进行全面验证,确保业务流程符合需求要求。

  • 性能测试

使用压力测试工具模拟多用户并发访问,重点测试系统的响应时间,吞吐量以及稳定性。

  • 安全测试

通过静态代码审查和动态扫描,检测系统中可能存在的安全漏洞,保证用户数据安全。

  • 兼容性测试

在主流浏览器,操作系统上进行测试,确保界面及功能均能正常适配。

4.测试工具

完成此测试项目采用的工具有Selenium WebDiver(自动化UI测试),JMeter(接口压力测试)

5.测试环境

硬件:LAPTOP-LFRKKJNQ (Ryzen 7 5800H/16GB/512GB/Radeon Graphics)

操作系统: Windows 11 家庭中文版

浏览器: Microsoft Edge 134.0.3124.72 (正式版本) (64 位)

自动化脚本运行环境: PyCharm 2022.1.4 (Community Edition) Python3.13

二、测试用例

1.用例设计方法

测试用例设计主要基于需求分析,结合等价类划分和边界值分析,确保覆盖有效和无效输入,同时通过场景测试模拟用户实际操作,提升测试的全面性和实用性。

下图为整体的测试用例:

2.功能测试用例

3.兼容性测试用例

4.易用性测试用例

5.性能测试用例

6.界面测试用例

7.安全性测试用例

三、手动测试

实际执行测试的部分操作步骤/截图

1.博客登录页

1.1正常登录

1.1.1输入正确的账号和密码
  • 步骤:在输入框输入正确的账号和密码
  • 预期结果:跳转至博客列表页
  • 实际结果:跳转至博客列表页,与预期结果一致
  • 结论:通过

1.2异常登录

1.2.1输入正确的账号和错误的密码
  • 步骤:在输入框输入正确的账号和错误的密码
  • 预期结果:弹出显示密码错误的警告弹窗
  • 实际结果:弹出显示密码错误的警告弹窗,与预期结果一致
  • 结论:通过
1.2.2输入错误的账号和错误的密码
  • 步骤:在输入框输入错误的账号和错误的密码
  • 预期结果:弹出显示用户不存在的警告弹窗
  • 实际结果:弹出显示用户不存在的警告弹窗,与预期结果一致
  • 结论:通过
1.2.3输入错误的账号和密码
  • 步骤:在输入框输入错误的账号和密码
  • 预期结果:弹出显示用户不存在的警告弹窗
  • 实际结果:弹出显示用户不存在的警告弹窗,与预期结果一致
  • 结论:通过
1.2.4输入空用户名
  • 步骤:在输入框输入空用户名
  • 预期结果:弹出显示账号或密码不能为空的警告弹窗
  • 实际结果:弹出显示账号或密码不能为空的警告弹窗,与预期结果一致
  • 结论:通过
1.2.5输入空密码
  • 步骤:在输入框输入空密码
  • 预期结果:弹出显示账号或密码不能为空的警告弹窗
  • 实际结果:弹出显示账号或密码不能为空的警告弹窗,与预期结果一致
  • 结论:通过

2.博客列表页

2.1登录状态下

  • 步骤:用户登录成功跳转至列表页后查看各个元素是否存在
  • 预期结果:最新发布的博客在最上方,以前发布的在下,各个元素均存在
  • 实际结果:最新发布的博客在最下方,以前发布的在上,各个元素均存在,与预期结果不一致
  • 结论:不通过

2.2未登录状态下

  • 步骤:点击右上角注销按钮,再点击主页按钮
  • 预期结果:跳转至用户登录页面
  • 实际结果:跳转至用户登录页面,与预期结果一致
  • 结论:通过

3.博客详情页

3.1登录状态下

  • 步骤:点击列表内任一博客下的查看全文按钮,查看各个元素是否存在
  • 预期结果:各个元素均存在
  • 实际结果:各个元素均存在,与预期结果一致
  • 结论:通过

3.2未登录状态下

  • 步骤:点击右上角注销按钮,再点击左上角导航回退按钮,点击任意博客下方的查看全文按钮
  • 预期结果:跳转至用户登录页面
  • 实际结果:跳转至用户登录页面,与预期结果一致
  • 结论:通过

4.博客编辑页

4.1登录状态下

4.1.1正常发布博客
  • 步骤:输入标题和内存,点击发布按钮
  • 预期结果:博客发布成功,博客列表新增新的博客
  • 实际结果:博客发布成功,博客列表新增新的博客,与预期结果一致
  • 结论:通过
4.1.2异常发布博客
4.1.2.1不写标题
  • 步骤:输入空标题,点击发布按钮
  • 预期结果:博客发布失败,博客列表不更新,弹出弹窗提示标题未填写
  • 实际结果:博客发布失败,博客列表不更新,弹出弹窗未显示提示,与预期结果不一致
  • 结论:不通过
4.1.2.2不写内容
  • 步骤:输入空内容,点击发布按钮
  • 预期结果:博客发布失败,博客列表不更新,弹出弹窗提示内容未填写
  • 实际结果:博客发布失败,博客列表不更新,弹出弹窗未显示提示,与预期结果不一致
  • 结论:不通过

4.2未登录状态下

  • 步骤:点击右上角注销按钮,再点击导航栏返回按钮,点击更新文章按钮
  • 预期结果:跳转至用户登录页面
  • 实际结果:跳转至用户登录页面,与预期结果一致
  • 结论:通过

四、自动化测试

  • 根据脑图创建自动化测试项目,编写自动化测试脚本。
  • 公共属性需要单独放一个类,方便进行代码复用。
  • 创建启动以及现场截图就是会频繁进行复用,单独创建一个类进行存储。
  • 注意添加隐式等待,为了确保页面正确加载显示。

1.测试用例

2.代码编写

2.1新建包并在包下创建测试文件及公共文件

2.2公共文件

  • 创建驱动对象

  • 添加隐式等待,可以作用于全局

  • 添加屏幕截图

  • 创建存放截图的文件夹images

  • 按照当天日的期作为文件名来创建子文件夹,这样方便按天查找截图

  • 按照调用方法+当天日期+时分秒的格式命名屏幕截图,方便按照调用方法查找截图,并且截图多的情况下不会被覆盖删除

    #创建一个浏览器对象
    import datetime
    import os.path
    import sys

    from selenium import webdriver
    from selenium.webdriver.chrome.service import Service
    from webdriver_manager.chrome import ChromeDriverManager

    class Driver:
    driver = ""
    def init(self):
    options = webdriver.ChromeOptions()
    self.driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()),options=options)
    self.driver.implicitly_wait(2)
    def getScreeShot(self):
    #创建屏幕截图
    #图片文件名称:./2024-05-08-173456.png
    dirname = datetime.datetime.now().strftime("%Y-%m-%d")
    #判断dirname文件夹是否已经存在,若不存在则创建文件夹
    # ../images/2024-05-08
    if not os.path.exists("../images/"+dirname):
    os.mkdir("../images/"+dirname)
    #2024-05-08-173456.png
    #图片路径:../images/调用方法-2024-05-08/2024-05-08-173456.png
    #图片路径:../images/LoginSucTest-2024-05-08/2024-05-08-173456.png
    #图片路径:../images/LoginFailTest-2024-05-08/2024-05-08-173456.png
    filename = sys._getframe().f_back.f_code.co_name+"-"+datetime.datetime.now().strftime("%Y-%m-%d-%H%M%S")+".png"
    self.driver.save_screenshot("../images/"+dirname+"/"+filename)

    BlogDriver = Driver()

2.3测试登录页面

  • 创建驱动访问博客系统登录页面

  • 测试页面是否可以正常打开

  • 使用不同参数测试是否成功登录

  • 异常登录

  • 注意清空内容后才能再次输入用户名以及密码

    import time

    from selenium.webdriver.common.by import By

    from common.Utils import BlogDriver
    #测试博客登陆页面

    class BlogLogin:
    url = ""
    driver = ""
    def init(self):
    self.url = "http://8.137.19.140:9090/blog_login.html"
    self.driver = BlogDriver.driver
    self.driver.get(self.url)
    #成功登陆的测试用例
    def LoginSucTest(self):
    self.driver.find_element(By.CSS_SELECTOR, "#username").clear()
    self.driver.find_element(By.CSS_SELECTOR, "#password").clear()

    复制代码
          self.driver.find_element(By.CSS_SELECTOR,"#username").send_keys("zhangsan")
          self.driver.find_element(By.CSS_SELECTOR,"#password").send_keys("123456")
          self.driver.find_element(By.CSS_SELECTOR,"#submit").click()
          #能够找到博客首页用户的昵称,说明登录成功,否则登录失败
          self.driver.find_element(By.CSS_SELECTOR,"body > div.container > div.left > div > h3")
          #添加屏幕截图
          #BlogDriver.getScreeShot()
          #返回到登陆页面
          self.driver.back()
    
      #异常登陆的测试用例
      def LoginFailTest(self):
          #若连续多次的send_keys则会出现关键词拼接,而不是替换。若要替换需要先clear
          self.driver.find_element(By.CSS_SELECTOR, "#username").clear()
          self.driver.find_element(By.CSS_SELECTOR, "#password").clear()
          self.driver.find_element(By.CSS_SELECTOR, "#username").send_keys("zhangsan")
          #错误的密码
          self.driver.find_element(By.CSS_SELECTOR, "#password").send_keys("1234")
          self.driver.find_element(By.CSS_SELECTOR, "#submit").click()
          time.sleep(1)  #页面渲染未完成 找不到弹窗应强制等待
          alert = self.driver.switch_to.alert
          alert.accept()
          # 切换到新窗口后
          new_window_url = self.driver.current_url
          if "http://8.137.19.140:9090/blog_list.html" in new_window_url:
              print("账号成功登录")
          else:
              print("账号异常登录")
          #添加屏幕截图
          BlogDriver.getScreeShot()

    #login = BlogLogin()
    #login.LoginSucTest()
    #login.LoginFailTest()

2.4测试博客首页

  • 分两种情况:登录状态和未登录状态(未登录状态点击"主页"应该跳转到登录页面)

  • 测试博客列表是否可以正常展示

  • 测试"查看全文"按钮是否可以正常跳转到博客详情页

  • 测试"注销"按钮是否可以正常跳转到博客登录页面

  • 测试"写博客"按钮是否可以正常跳转到写博客页面

  • 注意弹窗的渲染需要时间,所以需要添加强制等待

  • 测试博客标题、内容、个人信息(如昵称、头像)是否存在

  • 注意执行顺序

    from selenium.webdriver.common.by import By

    from common.Utils import BlogDriver
    #博客首页测试用例
    class BlogList:
    url = ""
    driver = ""
    def init(self):
    self.url = "http://8.137.19.140:9090/blog_list.html"
    self.driver = BlogDriver.driver
    self.driver.get(self.url)
    #测试首页(登录情况下)
    def ListTestByLogin(self):
    #测试博客标题是否存在
    self.driver.find_element(By.CSS_SELECTOR,"body > div.container > div.right > div:nth-child(1) > div.title")
    #测试博客内容是否存在
    self.driver.find_element(By.CSS_SELECTOR,"body > div.container > div.right > div:nth-child(1) > div.desc")
    #测试按钮是否存在
    self.driver.find_element(By.CSS_SELECTOR,"body > div.container > div.right > div:nth-child(1) > a")

    复制代码
          #个人信息-检查昵称是否存在
          self.driver.find_element(By.CSS_SELECTOR,"body > div.container > div.left > div > h3")
          #添加屏幕截图
          BlogDriver.getScreeShot()

2.5测试博客编辑页

  • 测试博客编辑页是否可以正常打开

  • 测试博客编辑页的基本元素是否存在(如菜单栏)

  • 测试博客是否可以正常发布

  • 测试博客内容或标题为空的时候是否还可以正常发布

  • 注意测试博客编辑页之前要先登录,否则后面会被登录页面覆盖

  • 注意执行顺序

    import time

    from selenium.webdriver.common.by import By

    from common.Utils import BlogDriver
    #测试博客编辑页面
    class BlogEdit:
    url = ""
    driver = ""
    def init(self):
    self.url = "http://8.137.19.140:9090/blog_edit.html"
    self.driver = BlogDriver.driver
    self.driver.get(self.url)

    复制代码
      #正确发布博客(登陆状态下)
      def EditSucTestByLogin(self):
          self.driver.find_element(By.CSS_SELECTOR,"#title").send_keys("zz自动化测试创建")
          #找到编辑区域,输入关键词(编辑区域不可操作)
          #菜单栏无法元素无法定位
          #博客系统编辑区域默认情况下就不为空,可以暂不处理
    
          #直接点击发布按钮来发布博客
          self.driver.find_element(By.CSS_SELECTOR,"#submit").click()
          #点击完成之后出现页面的跳转,页面跳转需要加载时间,可能会出现代码执行的速度比页面渲染的速度要快,导致元素查找不到,因此可以添加等待
          #添加隐式等待和显示等待都可以,任选择一个
          #隐式等待:创建浏览器对象之后就可以加上,因为隐式等待的作用域在driver整个生命周期
          #显示等待:可以作用在当前代码中
          actual=self.driver.find_element(By.CSS_SELECTOR,"body > div.container > div.right > div:nth-child(3) > div.title").text
          assert actual == "zz自动化测试创建"
          #屏幕截图
          BlogDriver.getScreeShot()
          self.driver.find_element(By.CSS_SELECTOR,"body > div.container > div.right > div:nth-child(3) > a").click()
          self.driver.find_element(By.CSS_SELECTOR,"body > div.container > div.right > div > div.operating > button:nth-child(2)").click()
          time.sleep(1)
          alert = self.driver.switch_to.alert
          alert.accept()

2.6测试博客详情页

  • 测试博客详情页是否可以正常打开

  • 测试博客标题、内容、发布时间是否存在

  • 测试博客再编辑和删除操作

  • 注意执行顺序

    from selenium.webdriver.common.by import By

    from common.Utils import BlogDriver
    #测试博客详情页
    class BlogDeail:
    url = ""
    driver = ""
    def init(self):
    self.url = "http://8.137.19.140:9090/blog_detail.html?blogId=165206"
    self.driver = BlogDriver.driver
    self.driver.get(self.url)

    复制代码
      #登陆状态下博客详情页的测试
      def DetailTestByLogin(self):
          #检查标题
          self.driver.find_element(By.CSS_SELECTOR,"body > div.container > div.right > div > div.title")
          #检查时间
          self.driver.find_element(By.CSS_SELECTOR,"body > div.container > div.right > div > div.date")
          #检查内容
          self.driver.find_element(By.CSS_SELECTOR,"#detail")
          #屏幕截图
          BlogDriver.getScreeShot()

2.7回归测试代码

复制代码
from tests import BlogLogin
from tests import BlogList
from tests import BlogDetail
from tests import BlogEdit
from common.Utils import BlogDriver

if __name__ == "__main__":
    #BlogLogin.BlogLogin().LoginFailTest()
    BlogLogin.BlogLogin().LoginSucTest()
    # #登陆成功之后就可以调用博客首页测试首页的用例(登陆状态)
    BlogList.BlogList().ListTestByLogin()
    # #测试登录状态下的博客详情页
    BlogDetail.BlogDeail().DetailTestByLogin()
    #博客编辑页面
    BlogEdit.BlogEdit().EditSucTestByLogin()
    #指定浏览器的退出
    BlogDriver.driver.quit()

五、性能测试

使用 JMeter 对博客系统进行了性能测试,模拟多用户并发访问。

对博客系统的主要接口:登录页、列表页、博客详情页、用户信息页、添加博客页,进行了性能测试。

5.1添加Http请求

添加博客系统登录页、博客系统用户详细页、博客系统列表页、博客系统详情页、添加博客5个接口http请求

5.2添加博客系统HTTP默认请求值

由于每个接口所使用的协议、IP和端口都是相同的,所以可以配置HTTP默认请求值的协议、IP和端口

5.3添加查看结果数

用于查看并发线程运行的结果

5.4添加JSON提取器

由于博客列表页的请求有时会取不到用户的登录凭证导致请求失败,未防止这种情况发生,需手动添加JSON提取器用来提取博客登录页返回数据中的用户登录凭证,提供给其他接口使用。

5.5添加HTTP信息头管理器

上述5.4添加了JSON提取器来提取用户登录凭证,这里的信息头管理器就是将提取到的内容自动的编写到各个接口的请求头部分。

5.6添加聚合报告

可以用来监听执行结果

5.7添加同步定时器

由此可以看出5组线程并非并发的执行,需要添加同步定时器来强制并发执行。

所有线程全部准备好之后,才可以并发的请求。

为保证线程可以并发的执行,需添加同步定时器。

需要注意同步定时里配置的用户数量不能超过所配置的线程组的数量,否则会一直等待线程准备就绪。

5.8建立梯度压测线程组

启动20个线程;1秒内启动5个线程,每隔3秒再启动一次;保持10秒;每隔1秒结束5个线程

5.9性能测试报告

六、项目Bug以及改进建议

6.1项目Bug

  • 博客编辑页,不填写标题或内容发布,出现的弹窗无提示语
  • 博客首页,博客内容排列顺序不符合用户习惯
  • 博客详情页,删除博客无删除成功提示,不符合用户习惯

6.2改进建议

6.2.1博客编辑页:弹窗无提示语

问题分析:

用户未填写标题或内容就点击 "发布",系统虽触发弹窗但无提示语,会导致用户困惑(不清楚未发布的原因),增加操作试错成本。

改进建议:

1.明确提示未填写项

  • 弹窗标题设为 "发布失败",正文根据缺失内容显示具体提示:
  • 若标题为空:"请填写博客标题后再发布"
  • 若内容为空:"请填写博客内容后再发布"
  • 若两者都为空:"请填写博客标题和内容后再发布"
  • 弹窗按钮统一为 "确定",点击后聚焦到未填写的输入框(如标题为空则光标自动定位到标题栏),减少用户操作路径。

2. 前置校验优化

  • 在 "发布" 按钮旁添加实时校验提示(无需点击发布):
  • 内容为空时,编辑器底部显示红色小字 "内容不能为空";
  • 标题为空时,标题输入框下方显示红色小字 "标题不能为空";
  • 未填写时 "发布" 按钮置灰(不可点击),鼠标悬停时显示 tooltip 提示 "请完善标题和内容",从源头避免无效操作。

6.2.3博客首页:内容排列顺序不符合用户习惯

问题分析:

博客首页排列顺序不符合用户习惯,可能导致用户难以快速找到最新 / 重要内容(常见合理顺序为 "按发布时间倒序",即最新发布的博客在最前)。

改进建议:

1.默认排序规则优化

  • 优先采用 "按发布时间倒序" 排列(最新发布的博客展示在首页顶部),符合多数用户 "关注最新内容" 的习惯;
  • 若系统支持 "按阅读量 / 点赞数排序",可作为可选规则,但默认保持 "时间倒序"。

2.提供排序切换功能

在首页顶部添加排序筛选栏,选项包括:

  • 点赞数最高
  • 阅读量最高
  • 最早发布
  • 最新发布(默认选中)
  • 选中某选项后,页面内容实时刷新并高亮当前选中项,满足不同用户的筛选需求。

3.视觉强化时间信息

  • 在每篇博客卡片的标题下方或角落,明确显示发布时间(如 "2024-05-20 15:30"),让用户直观感知排序逻辑,减少困惑。

6.2.4博客详情页:删除博客无删除成功提示

问题分析:

删除操作属于高风险操作,无成功提示会导致用户不确定操作是否生效(可能重复删除或误判未删除),影响操作安全感。

改进建议:

1.添加删除成功弹窗

点击 "删除" 并确认后,弹出提示窗:

  • 标题:"删除成功"
  • 正文:"该博客已永久删除,不可恢复"
  • 按钮:"确定"
  • 点击 "确定" 后,自动跳转至博客首页(或用户之前浏览的列表页),避免停留在已删除的详情页(此时页面可能空白或报错)。

2.删除前二次确认

  • 优化删除流程:点击 "删除" 按钮后,先弹出二次确认窗(防止误触):
    • 标题:"确认删除?"
    • 正文:"此操作不可撤销,是否确定删除该博客?"
    • 按钮:"取消"(左)、"确认删除"(右,红色强调)
  • 二次确认后再执行删除操作,降低误操作风险,同时配合后续的 "成功提示" 形成完整闭环。

3.首页同步反馈

  • 从详情页删除博客并跳转至首页后,在首页顶部显示临时通知条(如绿色背景文字):"'XXX(博客标题)'已成功删除",3 秒后自动消失,进一步强化操作结果感知。

七、测试结论

7.1功能测试结果

系统核心功能模块均通过全面测试验证,包括用户登录、博客编辑、博客查看及博客删除等关键功能,各模块功能实现完整且符合需求规格。

测试覆盖了各类业务场景,既包含正常操作流程(如成功登录、发布完整博客、正常浏览和删除博客),也涵盖了异常场景验证(如登录失败、博客内容为空提交等边界情况),未发现功能缺陷。

7.2自动化测试结果

所有设计的自动化测试用例执行完毕,全部通过验证,未发现功能异常,表明系统核心功能的稳定性和一致性得到保障,可支持后续持续迭代测试。

7.3性能测试结果

在高并发场景下,系统表现稳定,各项性能指标均在预设阈值范围内:

  • 系统无崩溃、死锁或数据不一致等严重问题
  • 页面响应时间和接口处理时间均处于可接受水平
  • 未出现明显的性能瓶颈,能够满足预期用户量的访问需求