一、项目背景
想要做一个属于自己的来存储私人博客的项目。基于SSM框架实现的个人博客系统,由四个页面构成:用户登录页、博客编辑页、博客列表页以及博客详情页。只要登录就可以查看并修改自己的博客,其他用户的博客只能查看。
但是该项目没有实现用户注册的功能,只能通过在数据库中存储的用户数据来进行校验登录并且用户的头像不能自己设定。用户的文章数量以及文章类型也是静态设定好的并不能直接修改。
通过使用selenium工具来定位到web中的元素,对获取到的元素进行自动化测试等操作。博客系统实现了发布个人博客并记录博客的标题、内容、发布时间、发布人等详细信息的功能。
二、设计测试用例
三、执行测试用例
1、博客登录页面测试
1.1 登陆界面
1.2 输入正确的账号和密码(账号:lisi,密码:123456)
预期结果:输入正确的账号和密码后并点击提交按钮,成功进入到博客首页
实际结果演示:
1.3 输入错误的账号和正确的密码(账号:admin,密码:123456)
预期结果:输入错误的账号和正确的密码后并点击提交按钮,弹出警告框并提示用户不存在。
实际结果演示:
1.4 输入正确的账号和错误的密码(账号:lisi,密码:123)
预期结果:输入正确的账号和错误的密码后并点击提交按钮,弹出警告框并提示密码错误。
实际结果演示:
1.5 输入错误的账号和错误的密码(账号:admin,密码:123)
预期结果:输入错误的账号和错误的密码后并点击提交按钮,弹出警告框并提示用户不存在。
实际结果演示:
1.6 不输入账号和密码
预期结果:不输入账号和密码后并点击提交按钮,弹出警告框并提示账号或密码不能为空。
实际结果演示:
2、博客列表页面测试
2.1 界面(成功登录后进入界面)
预计结果:展示了用户的昵称、头像、发布文章的数量、文章的分类和博客的标题、发布时间、内容等信息。
实际结果:
3、博客详情页面测试
3.1 界面(通过点击对应博客下方的查看全文按钮进入)
预计结果:查看的博客是当前用户发布的,显示博客的具体信息(标题、内容、发布时间),编辑按钮和删除按钮。
实际结果展示:
预计结果:查看的博客不是当前用户发布的,显示博客的具体信息(标题、内容、发布时间)
实际结果展示:
3.2 删除文章
预计结果:在当前用户发布的博客详情页中点击删除按钮并成功删除博客
实际结果展示:
4、博客编辑页面
4.1 界面(点击编辑按钮或点击写博客按钮进入)
预计结果:页面正常展示,编辑功能正常使用
实际结果展示:
4.2 输入博客的标题和内容
预计结果:标题和内容都不为空且字符都合法
实际结果展示:
4.3 点击发布文章按钮
预计结果:成功发布文章并自动跳回到博客列表页
实际结果展示:
四、基于Python和selenium的自动化测试
1、背景
若通过安装驱动的⽅式来启动浏览器,每次浏览器更新后对应的驱动也需要更新,为了解决这个问题,selenium中提供了驱动管理⼯具webdriver-manager,有了webdriver-manager⽆需⼿动安装浏览器驱动,即使浏览器更新也不会影响⾃动化的执⾏。
WebDriver Manager是⼀个开源的命令⾏⼯具,它可以⾃动下载和安装适⽤于不同浏览器的WebDriver。通过使⽤WebDriver Manager,我们可以确保浏览器驱动版本始终与浏览器版本保持⼀致,从⽽避免因版本不匹配⽽导致的各种问题
selenium是⼀个web⾃动化测试⼯具,selenium中提供了丰富的⽅法供给使⽤者进⾏web⾃动化测试。
2、创建新项目
首先得在新项目的设置里查看project:当前项目名中是否存在selenium和webdriver-manager这两个软件包
3、参照测试用例来编写自动化脚本
3.1 创建浏览器对象
想要执行一系列的自动化测试操作就得请求访问URL对应的页面,由于每个页面的自动化测试是独立进行且都要使用浏览器对象(多次创建浏览器对象会造成性能的消耗)。所以把浏览器对象的创建放在一个文件中(Until.py文件),这样在退出浏览器之前,各个文件只需要从Until.py文件调用即可。
有些时候自动化测试的返回结果有问题,我们需要了解具体是哪处页面出了问题,所以需要用到屏幕截图功能。这个功能也是实现在Until.py文件中。
- 首先实现一个类Driver
- 然后定义一个类成员driver和两个成员函数(一个是类的构造函数,另一个是调用获取屏幕截图的函数)
import datetime
import os.path
import sys
import time
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()
# 通过webdriver方法来选择打开Chrome浏览器
# 而打开Chrome有很多参数,只需要关注service(选择用什么样的服务打开Chrome)和option(浏览器的配置)即可
# Service函数有一个参数,这个参数是用创建好的驱动来打开Chrome
self.driver = webdriver.Chrome(service = Service(ChromeDriverManager().install()), options = options)
# 隐式等待2秒,等待页面加载
self.driver.implicitly_wait(3)
def GetScreenShot(self):
# 获取屏幕截图
dirName = datetime.datetime.now().strftime("%Y-%m-%d")
# 判断dirName文件夹是否存在,若不存在则创建文件夹
# ../images/2025-3-14
if not os.path.exists("../images/" + dirName):
os.mkdir("../images/" + dirName)
# 想要的截图文件夹名: 方法名 + 日期 + 时间 + .png
# ../images/LoginSucTest-2025-3-14-91325.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类中的成员
BlogDriver = Driver()
3.2 创建一个用于测试各种接口的文件(只运行这个文件)
- 文件名为:Run_Test.py
from BlogAutoTest.common.Utils import BlogDriver
if __name__ == "__main__":
3.3 博客登录页自动化测试
- 创建一个用于执行博客登录自动化测试的文件(文件名为:BlogLogin.py)
- 在文件中创建一个类(BlogLogin)用于在里面实现自动化测试的接口
- 引入Until.py文件和一些需要用到的包和依赖
- 在类里面分别编写两个用于测试登陆成功和登录失败的函数(测试用例)
- 需要注意的是在输入账号和密码前需要将输入框中的文本给删除
- 在对博客登录页进行测试时主要是对页面是否能正常打开和是否能正常登录
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 BlogAutoTest.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("lisi")
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.GetScreenShot()
# # 因为还要测试异常登录,所以需要从博客首页回退到博客登录页
# self.driver.back()
# 测试博客异常登录的测试用例
def LoginFailTest(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("lisi")
self.driver.find_element(By.CSS_SELECTOR, "#password").send_keys("1234")
self.driver.find_element(By.CSS_SELECTOR, "#submit").click()
# 由于隐式等待识别不了弹窗,所以只能用显示等待
wait = WebDriverWait(self.driver, 2)
wait.until(EC.alert_is_present())
alert = self.driver.switch_to.alert
# 检查下弹窗是否符合预期
assert alert.text == "密码错误"
# 在登录失败后会弹出警告框,需要点击确定后清除输入框内容再输入新的文本
alert.accept()
# 截图只能等点击弹窗后才能截图
# 发生错误可以通过截图来获取信息
BlogDriver.GetScreenShot()
# 在输入前先将输入框的文本删除
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("admin")
self.driver.find_element(By.CSS_SELECTOR, "#password").send_keys("123456")
self.driver.find_element(By.CSS_SELECTOR, "#submit").click()
# 由于隐式等待识别不了弹窗,所以只能用显示等待
wait = WebDriverWait(self.driver, 2)
wait.until(EC.alert_is_present())
alert = self.driver.switch_to.alert
# 检查下弹窗是否符合预期
assert alert.text == "用户不存在"
# 在登录失败后会弹出警告框,需要点击确定后清除输入框内容再输入新的文本
alert.accept()
# 截图只能等点击弹窗后才能截图
# 发生错误可以通过截图来获取信息
BlogDriver.GetScreenShot()
# 在输入前先将输入框的文本删除
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("admin")
self.driver.find_element(By.CSS_SELECTOR, "#password").send_keys("12345")
self.driver.find_element(By.CSS_SELECTOR, "#submit").click()
wait = WebDriverWait(self.driver, 2)
wait.until(EC.alert_is_present())
alert = self.driver.switch_to.alert
# 检查下弹窗是否符合预期
assert alert.text == "用户不存在"
# 在登录失败后会弹出警告框,需要点击确定后清除输入框内容再输入新的文本
alert.accept()
# 截图只能等点击弹窗后才能截图
# 发生错误可以通过截图来获取信息
BlogDriver.GetScreenShot()
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, "#submit").click()
wait = WebDriverWait(self.driver, 2)
wait.until(EC.alert_is_present())
alert = self.driver.switch_to.alert
assert alert.text == "账号或密码不能为空"
alert.accept()
BlogDriver.GetScreenShot()
# login = BlogLogin()
# login.LoginSucTest()
# login.LoginFailTest()
运行结果如下图所示:
3.4 博客列表页自动化测试
- 创建一个用于执行博客首页自动化测试的文件(文件名为:BlogList.py)
- 在文件中创建一个类(BlogList)用于在里面实现自动化测试的接口
- 引入Until.py文件和一些需要用到的包和依赖
- 在类里面分别编写两个用于测试登陆成功进入博客列表页和登录失败进入博客列表页的函数(测试用例)
- 测试的内容包括:如果登录成功,会显示登录用户的昵称,博客的标题、发布时间、内容以及查看全文按钮
import time
from selenium.webdriver.common.by import By
from BlogAutoTest.common.Utils import BlogDriver
# # 测试博客首页
class BlogList:
driver = ""
url = ""
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.left > div > h3")
# 是否有博客标题
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.date")
# 是否有"查看全文"按钮
self.driver.find_element(By.CSS_SELECTOR, "body > div.container > div.right > div:nth-child(1) > a")
# 文章数量是否为空
text = self.driver.find_element(By.CSS_SELECTOR, "body > div.container > div.left > div > div:nth-child(5) > span:nth-child(1)").text
# 打印文章具体数量
print(text)
assert text != 0
# 在未登录情况下进行测试
def ListTestByNotLogin(self):
# 自动跳转到博客登录页
self.driver.get("http://8.137.19.140:9090/blog_login.html")
测试结果如下图所示:
3.5 博客详情页自动化测试
- 创建一个用于执行博客详情页自动化测试的文件(文件名为:BlogDetail.py)
- 在文件中创建一个类(BlogDetail)用于在里面实现自动化测试的接口
- 引入Until.py文件和一些需要用到的包和依赖
- 在类里面分别编写两个用于测试登陆成功进入博客详情页和登录失败进入博客详情页的函数(测试用例)
- 需要注意的是每天博客系统都会删除当天发布的博客,所以通过URL进入博客详情页的时候就得更新URL末尾的blogid。
- 测试的内容包括:进入指定博客详情页后,是否展示博客的标题、发布时间、内容以及编辑按钮和删除按钮
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 BlogAutoTest.common.Utils import BlogDriver
# 测试博客详情页
class BlogDetail:
driver = ""
url = ""
def __init__(self):
self.driver =BlogDriver.driver
self.url = "http://8.137.19.140:9090/blog_detail.html?blogId=26615"
self.driver.get(self.url)
# 在登陆的情况下测试博客详情页
def BlogDetailByLogin(self):
# # 显示等待弹窗
# wait = WebDriverWait(self.driver, 2)
# wait.until(EC.alert_is_present())
#
# alert = self.driver.switch_to.alert
# alert.accept()
#
# # 点击“主页”按钮跳转至主页并点击想要查看文章的“查看全文”按钮进入博客详情页
# self.driver.find_element(By.CSS_SELECTOR, "body > div.nav > a:nth-child(4)").click()
# self.driver.find_element(By.CSS_SELECTOR, "body > div.container > div.right > div:nth-child(8) > a").click()
# 是否有“编辑”按钮
self.driver.find_element(By.CSS_SELECTOR, "body > div.container > div.right > div > div.operating > button:nth-child(1)")
# 是否有“删除”按钮
self.driver.find_element(By.CSS_SELECTOR, "body > div.container > div.right > div > div.operating > button: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.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, "#h2-u5728u8FD9u91CCu5199u4E0Bu4E00u7BC7u535Au5BA2")
# 添加截图
BlogDriver.GetScreenShot()
# 在未登陆的情况下测试博客详情页
def BlogDetailByNotLogin(self):
# 自动跳转到博客登录页
self.driver.get("http://8.137.19.140:9090/blog_login.html")
# 添加截图
BlogDriver.GetScreenShot()
执行结果如下图所示:
3.6 博客编辑页自动化测试
- 创建一个用于执行博客编辑页自动化测试的文件(文件名为:BlogEdit.py)
- 在文件中创建一个类(BlogEdit)用于在里面实现自动化测试的接口
- 引入Until.py文件和一些需要用到的包和依赖
- 在类里面分别编写两个用于测试登陆成功进入博客编辑页和登录失败进入博客编辑页的函数(测试用例)
- 测试内容包括:点击右上角写博客按钮或在博客详情页点击编辑按钮能否正常跳转到博客编辑页,点击发布文章按钮后是否正常跳转到博客列表页
from selenium.webdriver.common.by import By
from BlogAutoTest.common.Utils import BlogDriver
# 测试博客编辑页
class BlogEdit:
driver = ""
url = ""
def __init__(self):
self.driver = BlogDriver.driver
self.url = "http://8.137.19.140:9090/blog_edit.html"
self.driver.get(self.url)
# 在登陆成功的情况下测试博客编辑页
def BolgEditTestByLogin(self):
# 输入博客标题
self.driver.find_element(By.CSS_SELECTOR, "#title").send_keys("自动化测试")
# 找到编辑区域,输入关键词(编辑区域不可操作)
# 菜单栏无法元素无法定位
# 博客系统编辑区域默认情况下就不为空,可以暂不处理
# 可直接点击发布按钮来发布博客
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(1184) > div.title").text
assert actual == "自动化测试"
# 添加截图
BlogDriver.GetScreenShot()
# 在未登陆成功的情况下测试博客编辑页
def BolgEditTestByNotLogin(self):
# 自动跳转到博客登录页
self.driver.get("http://8.137.19.140:9090/blog_login.html")
# 添加截图
BlogDriver.GetScreenShot()
执行结果如下图所示: