一、项目背景
- 我的博客系统是一个典型的前后端分离的是一个Web项目。
- 由四个页面构成:博客登录页面、博客列表页面、博客详情页面、博客编辑页面。其主要功能有:登录、查看博客、编辑博客、发布博客以及删除博客等。
- 该系统涵盖了Web应用常见的核心模块,包括用户登录、数据操作(文章的增、删、改、查)、UI交互(表单填写、按钮点击、导航跳转)以及状态管理(登录前后界面差异)。这为自动化测试脚本的编写提供了丰富且具有代表性的场景。
二、项目功能
1. 登录页面
登录页面:
- 输入账号和密码登录(注:账号和密码直接写入数据库的,所以没有注册功能)
- 登录成功后跳转到博客列表页
- 菜单栏:在右上角存在主页(博客列表页)和写博客两个按钮
- 登录状态下:点击主页可以跳转到博客详情页;点击写博客可以跳转到博客编辑页
- 未登录状态下:点击主页不跳转,强制登录
2. 博客列表页
博客列表页:
- 登录状态下:页面才可以正常打开。在博客列表可以看到三个模块。
- 个人信息模块:可以看到登录的用户名,头像,以及已发布的文章数和文章分类
- 博客列表模块:可以看到博客标题、博客发布时间、博客内容,还可以通过“查看全文”按钮查看详细的博客无安稳
- 菜单栏:有三个按钮,分别是编写博客,点击编写博客可以跳转到博客编辑页面;点击主页可以回到博客列表;点击注销跳转到登录页面,重新登录
- 未登录状态下:强制用户登录,直接跳转到登录页面
3. 博客详情页
博客详情页:
- 登录状态下:在博客列表点击“查看全文”或直接输入链接就可以进入博客详情页。在博客详情页,可以看到博客标题、发布时间、博客内容,并且在文章内容后面有两个按钮。一个“编辑”按钮点击可以修改博客,一个“删除按钮”,点击会出现一个删除确认框,确认则删除博客回到博客列表页,取消则不删除不跳转。
- 未登录状态下:强制用户登录,直接跳转到登录页面
4. 博客编辑页
博客编辑页:
- 登录状态下:在任意界面点击“写博客”进入博客编辑页,此时可以编写博客标题,博客内容。如果要发布文章,必须标题和内容均不为空,最后点击发布文章即可发布成功。
- 未登录状态下:在登录页面点击“写博客”按钮也可以进入博客编辑页,但是不能编写博客、发布博客。未登录做编写/发布博客操作,跳转到登录页面,强制登录。
三、测试计划
测试计划:
- 设计自动化测试用例
- 工具:脑图/思维导图
- 参考测试用例,创建自动化测试项目,编写自动化测试脚本
- 工具:PyCharm、selenium库
1. 编写web测试用例

2. 编写自动化脚本
参考测试用例,创建自动化测试项目,编写自动化测试脚本
- 一个页面一个测试类
- BlogLogin.py:博客登录页面相关测试用例
- BlogList.py:博客列表页面相关测试用例
- BlogDetail.py:博客详情页面相关测试用例
- BlogEdit.py:博客编辑页面相关测试用例
- 将生成测试文件中需要用到的配置内容放在一个Utils.py工具类
2.1 工具类Utils.py
- 创建驱动:每一个页面都会创建浏览器对象,请求url访问对应的页面,进入到对应页面之后,才可以执行一系列的测试用例
- 截图保存:方便问题溯源
a. 图片路径:…/images/调用方法-2025-10-15-156777.png
b. 先建立一个images目录存放所有截图
c. 根据每天的日期进行分类,当天运行的自动化图片文件放到当天的文件夹下
d. 拼接调用的方法名,快速定位到是哪一个用例的截图
import datetime
import os
import sys
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
# 创建一个浏览器对象
class Driver:
driver = ""
def __init__(self):
driver_path = "D:\\ChromeDriver\\chromedriver.exe"
service = Service(executable_path=driver_path)
# 浏览器参数设置
options = webdriver.ChromeOptions()
self.driver = webdriver.Chrome(service=service, options=options)
#隐式等待
self.driver.implicitly_wait(3)
# 创建屏幕截图
def getScreeShot(self):
# 图片路径:../images/调用方法-2025-10-15-156777.png
dirname = datetime.datetime.now().strftime("%Y-%m-%d")
# 判断dirname文件夹是否已经存在,若不存在则创建文件夹
if not os.path.exists("../images/"+dirname):
os.mkdir("../images/"+dirname)
# sys._getframe().f_back.f_code.co_name获取调用的方法名
# 截图名称
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)
# 全局Driver实例
BlogDriver = Driver()
2.2 登录页面测试类BlogLogin.py
- 调用工具类创建驱动,并打开页面
- 创建成功登录的测试用例脚本
- 创建异常登录的测试用例脚本
# 测试博客登录页面
from selenium.webdriver.common.by import By
import time
from selenium.webdriver.support.expected_conditions import alert_is_present
from selenium.webdriver.support.wait import WebDriverWait
from commin.Utils import BlogDriver
class BlogLogin:
url = ""
driver = ""
def __init__(self):
self.url ="http://8.137.19.140:9090/blog_login.html"
# BlogDriver.driver.get(self.url)
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()
# 检测是否成功
# 登录成功,跳转到博客首页,并能在博客首页找到个人信息模块的“账号”, 否则登录失败
# time.sleep(2)
self.driver.find_element(By.CSS_SELECTOR, "body > div.container > div.left > div > h3")
# 添加屏幕截图
BlogDriver.getScreeShot()
#self.driver.quit()
# 返回登录页面
# time.sleep(2)
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("123")
# 点击提交
self.driver.find_element(By.CSS_SELECTOR, "#submit").click()
# 避免截图失败
time.sleep(3)
# 检查是否登录失败
alert = self.driver.switch_to.alert
# 打印弹窗内容(调试用)
print("弹窗内容:", alert.text)
#确认
alert.accept()
# 添加屏幕截图
# 调用 getScreeShot()时,可能会遇到弹窗(Alert)导致截图失败
BlogDriver.getScreeShot()
# self.driver.quit()
# 测试
# login = BlogLogin()
# login.LoginSucTest()
# login.LoginFailTest()
2.3 博客列表页面类BlogList.py
- 调用工具类创建驱动,并打开页面
- 创建登录状态下的博客列表的测试脚本
- 创建未登录状态下的博客列表的测试脚本
# 测试博客列表页面
from selenium.webdriver.common.by import By
from commin.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):
import time
time.sleep(1)
# 测试博客列表模块的博客标题是否存在
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()
# 点击菜单栏模块的“写博客”,是否跳转到编写页面
self.driver.find_element(By.CSS_SELECTOR,"body > div.nav > a:nth-child(5)").click()
# 获取当前页面URL current_url
url = self.driver.current_url
print(url)
assert url == "http://8.137.19.140:9090/blog_edit.html"
# 添加屏幕截图
BlogDriver.getScreeShot()
# 未登录状态下,强制登录
def ListTestByNotLogin(self):
# 获取当前页面URL current_url
url = self.driver.current_url
print(url)
assert url == "http://8.137.19.140:9090/blog_login.html"
# 添加屏幕截图
BlogDriver.getScreeShot()
# 指定浏览器的退出
BlogDriver.driver.quit()
# 测试
list = BlogList()
# list.ListTestByLogin()
list.ListTestByNotLogin()
2.4 博客编辑页类BlogEdit.py
- 调用工具类创建驱动,并打开页面
- 创建博客是否可以正确发布的测试脚本
# 测试博客编辑页面
from selenium.webdriver.common.by import By
import time
from commin.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("自动化测试创建")
# 输入内容
# 编辑区域不可编辑,但通过点击菜单栏可达到编辑区域不为空的目的
# 但菜单栏无法元素定位
# 博客系统编辑区域默认情况下就不为空,可以暂不处理
# self.driver.find_element(By.CSS_SELECTOR,"#editor > div.editormd-toolbar > div > ul > li:nth-child(7)").send_keys("自动化自动化自动化")
time.sleep(2)
# 点击发布按钮来发布博客
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(5) > div.title").text
assert actual == "自动化测试创建"
# 屏幕截图
BlogDriver.getScreeShot()
time.sleep(2)
2.5 博客详情页类BlogDetail.py
- 调用工具类创建驱动,并打开页面
- 创建测试编辑页是否正确打开的测试脚本
- 测试“删除”按钮是否可以正常使用
- 测试“编辑”按钮是否可以正常跳转
# 测试博客详情页
from selenium.webdriver.common.by import By
from commin.Utils import BlogDriver
class BlogDetail:
url = ""
driver = ""
def __init__(self):
self.url = "http://8.137.19.140:9090/blog_detail.html?blogId=158477"
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 > p")
# 屏幕截图
BlogDriver.getScreeShot()
# 丰登录状态下
2.6 测试套件类RunTest.py
# 程序执行入口
from commin.Utils import BlogDriver
from tests import BlogList
from tests import BlogLogin
from tests import BlogDetail
from tests import BlogEdit
if __name__ == "__main__":
BlogLogin.BlogLogin().LoginFailTest()
BlogLogin.BlogLogin().LoginSucTest()
# # 登录成功之后调用博客列表页测试用例
BlogList.BlogList().ListTestByLogin()
# # 登录成功之后调用博客详情页
BlogDetail.BlogDetail().DetailTestByLogin()
# 测试博客编辑页
BlogEdit.BlogEdit().EditSucTestByLogin()
# 指定浏览器的退出
BlogDriver.driver.quit()
3. 代码测试
所有测试用例均通过。
四、小结
- 注意测试用例的执行顺序
- 驱动关闭的位置要注意,一般放在最后一个用例测试结束才关闭
- 屏幕截图的保存方式:按照一天一个目录存放截图,并且截图名字拼接调用的方法名,方便快速定位问题
- 在创建对象之后使用隐式等待,避免出现代码执行的速度比页面渲染的速度快,导致元素找不到
- 只创建一次驱动对象,避免每个用例重复创建驱动造成时间和资源的浪费
- 在重要的测试后面添加屏幕截图
- 若连续多次的send_keys则会出现将关键词连接的情况,而不是替换。若要替换需要先clear。建议在输入之前都清空
- 调用屏幕截图,可能会遇到弹窗(Alert)导致截图失败,可在前面加强制等待
- 使用思维导图,覆盖大多数功能测试
2256

被折叠的 条评论
为什么被折叠?



