目录
1、项目背景
此次开发的博客系统是一个轻量级的内容管理平台,主要是在为用户提供便捷的文章发布、分享知识和记录生活等功能
2、项目简介
系统包含五个核心页面:用户登录页 、博客发布页 、博客编辑页 、博客列表页 和博客详情页。
用户登录页 :用户输入用户名和密码进行登录。错误处理:输入错误密码时提示「用户名或密码错误」,连续5次失败后锁定账号10分钟。
**博客发布页:**用户可输入博客标题、正文内容、添加标签(如#技术、#生活)或选择已有分类。点击「发布」按钮提交至后台,成功后跳转到博客详情页。
博客编辑页: 加载已有博客内容(标题、正文、标签等)供用户修改。点击「更新」按钮后覆盖原内容。**权限控制:**仅博客作者和管理员可编辑,其他用户访问时返回403错误。
**博客列表页:**分页展示所有公开博客(默认按发布时间倒序)。点击博客标题或「阅读更多」跳转至详情页。
**博客详情页:**展示博客完整内容(标题、作者、发布时间、正文、标签)。
编写测试用例
设计测试用例一般需要包含:界面测试,功能测试,性能测试,兼容性测试,安全性测试,易用性测试等
执行测试用例
手工执行测试用例
1、登录测试
异常登录测试:
1、输入正确的用户名和错误的密码(用户名:lisi,密码:123)
预期结果:页面弹出错误提示:密码错误

实际结果:页面弹出错误提示:密码错误。测试通过
2、输入错误的用户名和正确的密码(用户名:zs,密码:123456)
预期结果:页面弹出错误提示:用户不存在

实际结果:页面弹出错误提示:用户不存在。测试通过
正常登录
1、输入正确的用户名和密码(用户名:lisi,密码:123456)
预期结果:成功登录则跳转到博客首页

实际结果:成功登录则跳转到列表页,测试通过
博客首页
成功登录后跳转到博客首页,见上图
预期结果:
博客首页可以看到当前用户博客文章、分类的数量。当前用户的头像、用户名、查看已发布博客的有限博客信息(包括标题、日期、内容)、查看全文按钮等。
实际结果:
文章数量和分类显示数量错误。测试不通过
博客编辑页
在页面右上角点击"写博客",即可进入博客编辑页面,用户可以进行写文章操作。
博客编辑页各个功能是否正确可以显示且功能是否正常
预期结果:页面正常显示,有输入标题和内容的文本框,有工具栏,有发布文章按钮

实际结果:页面正常显示,有输入标题和内容的文本框,有工具栏,有发布文章按钮。测试通过
异常编写博客提交失败
1、不写标题点击发布文章
预期结果:出现提示弹窗点击确定返回博客编辑页

实际结果:出现提示弹窗点击确定返回博客编辑页。测试通过
2、不写内容点击发布文章
预期结果:出现提示弹窗点击确定返回博客编辑页

实际结果:出现提示弹窗点击确定返回博客编辑页。测试通过
正常编写博客发布文章
1、写上合法标题和合法的内容,点击发布文章
预期结果:成功发布,并且跳转到博客首页

实际结果:成功发布,并且跳转到博客首页。测试通过
博客详情页
选择任意一篇博客,点击"查看全文"按钮,即可进入博客详情页,此时可以看到该篇博客的所有内容。如果所查看的文章所是当前用户发布的,即可进行"编辑"和"删除"操作,如果所查看的文章是其他用户所发布的,则对文章的权限是"只读"。
查看当前用户发布的博客
预期结果:可以看到博客所有内容,还可进行"编辑"和"删除"操作

实际结果:可以看到博客所有内容,还可进行"编辑"和"删除"操作。测试通过
查看非当前用户发布的博客
预期结果:可以看到博客的所有内容,但没有编辑和删除按钮

实际结果:可以看到博客的所有内容,但没有编辑和删除按钮。测试通过
BUG简述
本次项目手工测试阶段发现了bug,0个崩溃级别的bug,0个严重级别的bug,1个一般级别的bug
|-------------|-----|------|
| bug标题 | 报告人 | 是否修复 |
| 文章和分类数量显示异常 | 何浩华 | 修改完成 |
[bug表单]
自动化执行测试用例
自动化测试简介
自动化测试是指利用脚本和工具(如 Selenium、Cypress、Postman、JMeter)自动执行测试用例,减少人工干预,提高测试速度和可重复性。
-
相比手工测试,自动化测试可以在几分钟内完成数百个用例的执行(如批量测试不同浏览器的兼容性)。
✅ 高覆盖率:
-
可覆盖复杂场景(如并发用户测试、大数据量查询),手工测试难以模拟。
✅ 可重复性:
-
相同的测试脚本可以反复运行,确保每次代码变更后的一致性。
✅ 持续集成(CI/CD)支持:
-
结合 Jenkins/GitHub Actions ,可在代码提交后自动触发测试,快速发现BUG。
✅ 减少人为错误:
-
避免手工测试中的遗漏或误操作(如忘记测试某个边界条件)。
使用Selenium进行自动化测试
本次测试环境
Selenium:4.0.0
python:3.10.11
PyCharm Community Edition 2024.3.5
环境配置
安装驱动管理(建议使用国内pypi镜像源下载,速度更快,因为官方源在国外)
作者用的是清华大学的pip镜像源
在windows powershell命令工具中输入
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ webdriver-manager
安装selenium库,selenium版本很多,作者用的是4.0.0版本
在windows powershell命令工具中输入
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ selenium==4.0.0
下载完成后打开PyCharm Community Edition 软件,点击菜单左上角文件-设置-项目-python解释器
检查python解释器,确定selenium库和WebDriverManager库都安装成功并加载到当前项⽬中

看到作者有标红的就说明环境配置完成,就可以写对应的自动化脚本了
下面可以简单写一个脚本看看是否能够脚本正常运行
python
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager
#驱动程序管理的⾃动化
#创建驱动对象
#1.打开浏览器
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
#2.输⼊百度⽹址:https://www.baidu.com
driver.get("https://www.baidu.com")
#3、找到输⼊框并输⼊"章若楠"
driver.find_element(By.CSS_SELECTOR,"#kw").send_keys("章若楠")
#4、找到"百度⼀下"按钮并点击
driver.find_element(By.CSS_SELECTOR,"#su").click()
#退出浏览器
#driver.quit()
编写自动化测试脚本
避免重复创建和销毁浏览器实例的开销。防止多个浏览器窗口同时存在导致资源浪费或操作冲突。在 Web 自动化测试中,通常只需要一个浏览器实例贯穿整个测试流程。
新建项目,项目中创建了一个名为common
的包,在其中放置了utils
模块。在utils
文件夹里,定义一个Driver
类,该类包含一个构造方法,用于初始化浏览器实例以便后续复用;同时还封装了一个截图功能的方法,以便在自动化测试过程中轻松捕获页面截图,便于排查问题。
python
# 导入必要的模块
import datetime # 用于处理日期和时间
import os # 用于操作系统相关功能(如文件路径操作)
import sys # 用于访问Python解释器相关的功能
from os import mkdir # 专门导入mkdir函数用于创建目录
from requests import options # 导入requests库的options(虽然代码中未使用)
from selenium import webdriver # 导入Selenium的WebDriver
from selenium.webdriver.edge.service import Service # Edge浏览器的服务类
from webdriver_manager.microsoft import EdgeChromiumDriverManager # Edge驱动管理
class Driver:
# 类变量,用于存储WebDriver实例
driver = ""
def __init__(self):
# 初始化Edge浏览器选项
options = webdriver.EdgeOptions()
# 添加允许远程源的参数(用于解决某些跨域问题)
options.add_argument("--remote-allow-origins=*")
# 创建Edge浏览器实例
# 使用EdgeChromiumDriverManager自动管理驱动版本
# 传入配置好的options
self.driver = webdriver.Edge(service=Service(EdgeChromiumDriverManager().install()), options=options)
def GetScreenshot(self):
# 获取当前日期,格式为"年-月-日"(如"25-04-25")
dirname = datetime.datetime.now().strftime("%y-%m-%d")
# 检查图片存储目录是否存在
# 完整路径为"../images/年-月-日"
if not os.path.exists("../images/" + dirname):
# 如果不存在则创建目录
os.mkdir("../images/" + dirname)
# 生成文件名:
# 1. 获取调用此方法的方法名(通过调用栈回溯)
# 2. 加上当前时间的"年-月-日-时分秒"格式
filename = sys._getframe().f_back.f_code.co_name + "-" + datetime.datetime.now().strftime("%y-%m-%d-%H%M%S")
# 保存截图到指定路径
# 格式:"../images/年-月-日/调用方法名-年-月-日-时分秒.png"
self.driver.save_screenshot("../images/" + dirname + "/" + filename + ".png")
# 创建Driver类的实例
Blogdriver = Driver()
登录功能自动化测试
python
import time
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from common.Utils import Blogdriver
class BlogLogin:
driver = ""
url = ""
def __init__(self):
self.url = "http://8.137.19.140:9090/blog_login.html"
self.driver = Blogdriver.driver
self.driver.get(self.url)
def SucLoginTest(self):
self.driver.find_element(By.CSS_SELECTOR,"#username").clear()
self.driver.find_element(By.CSS_SELECTOR,"#username").send_keys("zhangsan")
self.driver.find_element(By.CSS_SELECTOR,"#password").clear()
self.driver.find_element(By.CSS_SELECTOR,"#password").send_keys("123456")
self.driver.find_element(By.CSS_SELECTOR,"#submit").click()
time.sleep(2)
Blogdriver.GetScreenshot()
def FailLoginTest1(self):
#send_keys如果不清楚,就会把输入的内容拼接起来
#使用clear清楚
self.driver.find_element(By.CSS_SELECTOR,"#username").clear()
self.driver.find_element(By.CSS_SELECTOR,"#username").send_keys("zhangsan")
self.driver.find_element(By.CSS_SELECTOR,"#password").clear()
self.driver.find_element(By.CSS_SELECTOR,"#password").send_keys("123")
self.driver.find_element(By.CSS_SELECTOR,"#submit").click()
#等待弹窗加载出来,不然程序执行的速度太快可能没有找到弹窗
#添加显示等待
wait = WebDriverWait(self.driver,3)
#EC.alert_is_present()检查是否出现弹窗,如果出现那么就返回这个弹窗,否则抛异常
alert = wait.until(EC.alert_is_present())
alertTest = alert.text
#确认是否登录失败
#注意:先断言在确认弹窗
assert alertTest == "密码错误"
#确认弹窗
alert.accept()
Blogdriver.GetScreenshot()
def FailLoginTest2(self):
#send_keys如果不清楚,就会把输入的内容拼接起来
#使用clear清楚
self.driver.find_element(By.CSS_SELECTOR,"#username").clear()
self.driver.find_element(By.CSS_SELECTOR,"#username").send_keys("zhangsa")
self.driver.find_element(By.CSS_SELECTOR,"#password").clear()
self.driver.find_element(By.CSS_SELECTOR,"#password").send_keys("123456")
self.driver.find_element(By.CSS_SELECTOR,"#submit").click()
#等待弹窗加载出来,不然程序执行的速度太快可能没有找到弹窗
#添加显示等待
wait = WebDriverWait(self.driver,3)
#EC.alert_is_present()检查是否出现弹窗,如果出现那么就返回这个弹窗,否则抛异常
alert = wait.until(EC.alert_is_present())
alertTest = alert.text
#确认是否登录失败
#注意:先断言在确认弹窗
assert alertTest == "用户不存在"
#确认弹窗
alert.accept()
#获取截图
Blogdriver.GetScreenshot()
# Login = BlogLogin()
# Login.FailLoginTest1()
# Login.FailLoginTest2()
# Login.SucLoginTest()
博客首页自动化测试
python
import time
from telnetlib import EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from common.Utils import Blogdriver
from test.BlogLogin import BlogLogin
class BlogMain:
def __init__(self):
driver = ""
url = ""
self.driver = Blogdriver.driver
self.url = "http://8.137.19.140:9090/blog_list.html"
self.driver.get(self.url)
def CheckSecLoginMain(self):
self.driver.find_element(By.CSS_SELECTOR,"body > div.container > div.left > div > img")
self.driver.find_element(By.CSS_SELECTOR,"body > div.container > div.left > div > a")
self.driver.find_element(By.CSS_SELECTOR,"body > div.container > div.left > div > div:nth-child(4) > span:nth-child(1)")
self.driver.find_element(By.CSS_SELECTOR,"body > div.container > div.left > div > div:nth-child(4) > span:nth-child(2)")
self.driver.find_element(By.CSS_SELECTOR,"body > div.container > div.left > div > h3")
self.driver.find_element(By.CSS_SELECTOR,"body > div.nav > a:nth-child(4)")
self.driver.find_element(By.CSS_SELECTOR,"body > div.nav > a:nth-child(5)")
self.driver.find_element(By.CSS_SELECTOR,"body > div.nav > a:nth-child(6)")
# WebDriverWait(self.driver, 20).until(
# EC.presence_of_element_located((By.ID, "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.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.right > div:nth-child(1) > div.date")
self.driver.quit()
# BlogMain = Main()
# BlogLogin().SucLoginTest()
# BlogMain.CheckSecLoginMain()
博客查看全文、编辑页、更新文章自动化测试
import time
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from common.Utils import Blogdriver
from test.BlogLogin import BlogLogin
from test.BlogMain import BlogMain
class BlogDetail:
def __init__(self):
driver = ""
url = ""
self.driver = Blogdriver.driver
self.url = "http://8.137.19.140:9090/blog_detail.html?blogId=97185"
self.driver.get(self.url)
def DetailReadText(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")
wait = WebDriverWait(self.driver, 20)
# invisibility_of_element 是等待元素不可见:等待 弹窗或提示框 自动关闭。等待 临时元素(如进度条、Toast 提示)消失后再继续操作。
# visibility_of_element_located等待元素可见:确保元素 可以被点击或交互(如按钮、输入框)。
#添加显示等待
wait.until(EC.visibility_of_element_located((By.XPATH, '/html/body/div[2]/div[2]/div/div[4]/button[1]')))
#进入编辑页
self.driver.find_element(By.CSS_SELECTOR,"body > div.container > div.right > div > div.operating > button:nth-child(1)").click()
# time.sleep(4)
wait = WebDriverWait(self.driver,10)
wait.until(EC.visibility_of_element_located((By.XPATH,'//*[@id="editor"]/div[1]/div[6]')))
#输入内容
self.driver.find_element(By.CSS_SELECTOR,"#editor > div.CodeMirror.cm-s-default.CodeMirror-wrap > div.CodeMirror-scroll").send_keys("自动化测试更新文章")
#点击更新文章
self.driver.find_element(By.CSS_SELECTOR,"#submit").click()
time.sleep(3)
# self.driver.quit()
# Detail = BlogDetail()
# Main = BlogMain()
# Login = BlogLogin()
# Login.SucLoginTest()
# Main.CheckSecLoginMain()
# Detail.DetailReadText()
发布博客自动化测试
import time
from selenium.webdriver.common.by import By
from common.Utils import Blogdriver
from test.BlogDetail import BlogDetail
from test.BlogLogin import BlogLogin
from test.BlogMain import BlogMain
class BlogPulish:
def __init__(self):
url = ""
driver = ""
self.url = "http://8.137.19.140:9090/blog_list.html"
self.driver = Blogdriver.driver
self.driver.get(self.url)
def Publish(self):
self.driver.find_element(By.CSS_SELECTOR,"body > div.nav > a:nth-child(5)").click()
time.sleep(10)
self.driver.find_element(By.CSS_SELECTOR,"#title").send_keys("自动化测试")
#self.driver.find_element(By.CSS_SELECTOR,"#editor > div.CodeMirror.cm-s-default.CodeMirror-wrap > div.CodeMirror-scroll > div.CodeMirror-sizer > div > div > div > div.CodeMirror-code > div > pre > span > span").send_keys("完成自动化")
self.driver.find_element(By.CSS_SELECTOR,"#submit").click()
在runtest.py文件整体运行
python
from test.BlogDetail import BlogDetail
from test.BlogLogin import BlogLogin
from test.BlogMain import BlogMain
from test.BlogPublish import BlogPulish
if __name__ == "__main__":
BlogLogin().FailLoginTest1()
BlogLogin().FailLoginTest2()
BlogLogin().SucLoginTest()
BlogMain().CheckSecLoginMain()
BlogDetail().DetailReadText()
BlogPulish().Publish()
selenium+驱动+浏览器的⼯作原理
实现web⾃动化测试需要浏览器、浏览器驱动、selenium⾃动化脚本。这三者是如何交互最终实现 web的⾃动化测试?
-
通过selenium编写的⾃动化脚本代码中在ChromeDriverService中创建⼀个服务
-
通过创建好的服务打开webdriver,安装在本地的驱动服务IP为localhost,PORT为 ChromeDriverService中创建的端⼝号,该服务地址为selenium向webdriver发送请求的服务地 址。
-
向浏览器驱动程序发送HTTP请求,浏览器驱动程序解析请求,打开浏览器,并获得sessionid,如 果再次对浏览器操作需携带此id
-
打开浏览器后,所有的selenium的操作(访问地址,查找元素等)均通过创建好的服务链接到 webdriver,然后使⽤execute发送请求
-
驱动收到请求并对请求进⾏解析,转成浏览器能够解析的脚本并发送给浏览器,浏览器通过请求的 内容执⾏对应动作
6.浏览器再把执⾏的动作结果通过浏览器驱动程序返回给测试脚本
简单的流程图
+-----------------------+
| 自动化测试脚本 |
| (Selenium Client) |
+-----------+-----------+
| (1) 创建ChromeDriverService
| (localhost:PORT)
v
+-----------------------+
| ChromeDriverService |
| (HTTP Server) |
+-----------+-----------+
| (2) WebDriver API请求
| (携带Session ID)
v
+-----------------------+
| 浏览器驱动程序 |
| (ChromeDriver) |
+-----------+-----------+
| (3) 转成浏览器可执行脚本
| (如DevTools Protocol)
v
+-----------------------+
| 浏览器 |
| (Chrome/Firefox等) |
+-----------+-----------+
| (4) 执行动作并返回结果
v
+-----------------------+
| 返回结果给测试脚本 |
+-----------------------+