个人博客系统系统~测试报告
目录
1.项目的测试背景
2.手动对项目功能进行Web的基本功能测试
2.1 如何设计测试用例
2.2设计个人博客系统测试用例思维导图如下:
2.3 登录页面测试
2.4 博客列表页面测试
2.5 博客详情页面测试(点击博客列表页的查看全文进入)
2.6 博客编辑页面测试
2.6.1 发布博客测试
2.6.2 删除博客测试
2.5 博客退出功能测试
3. 使用Selenium进行Web自动化测试(Python)
3.1新建项目
3.2 参照测试用例,编写自动化脚本
3.2.1 创建驱动对象
3.2.2 创建驱动对象步骤
3.2.3 博客登录的自动化测试
3.2.4 博客列表页的自动化测试
3.2.4 博客详情页的自动化测试
3.2.5 博客编辑页的自动化测试
3.2.5 博客退出的的自动化测试
4.相比手动测试自动化测试的特点和优点
5.使用jmeter对博客系统进行性能测试
5.1 在jmeter里面测试登录页面接口
5.1.1 测试博客登录页接口
5.1.2 测试博客列表页接口
5.1.3 测试博客用户个人信息接口
5.1.4 测试添加JSON断言
5.1.5 添加CSV数据文件设置
6.完整的自动化测试代码链接
1.项目的测试背景
个人的博客系统是在SSM框架(这里借用了每天喝八杯水博主的SSM框架介绍的博客,已经设置了超链接大家感兴趣的可以点击观摩)的基础上实现的,博客系统由五个页面构成:用户登录页面,博客列表页面,博客详情页面,博客编辑页面,博客发布页,为了验证个人博客系统的功能是否正常,现在对博客系统进行手动和自动化测试,以便用户使用博客系统进行登录,项目的具体测试内容为:博客系统的登录,博客列表页和博客详情页还有博客编辑页的页面呈现和功能,写博客,删除博客,退出博客登录的功能是否正常,个人博客系统可以实现发布个人博客,记录博客发布日期、时间、标题、博客发布者等信息。
2.手动对项目功能进行Web的基本功能测试
2.1 如何设计测试用例
设计设计测试用例一般从6个方面进行设计:
功能测试,界面测试,性能测试,易用性测试,安全测试,兼容性测试等6个方面进行设计测试,个人实现的博客系统是一个web网址,我们主要对核心功能进行测试
2.2设计个人博客系统测试用例思维导图如下:
基于个人博客系统的页面进行功能测试设计:

2.3 登录页面测试
(简介)因为账号和密码都已经储存在数据库里面,只要对应的输入框输入正常的账号和密码就可以,跳转到博客列表页了。
(a)登录界面展示:
(b)在对应的输入框输入正常的账号和密码:(账号:zhangsan密码:123456)
预期效果:跳转到博客列表页
实际效果展示:
(c)c1:输入正常的账号和错误的密码:(账号:zhangsan密码:12345)
预期结果:账号或者密码错误
实际结果展示:
(c2):输入错误的账号和正确的密码:(账号:wangwu密码:123456)
预期结果:账号不存在
实际结果展示:
(c3):输入错误的账号和错误的密码:(账号:wangwu密码:12345)
预期的结果:账户不存在
实际结果展示:
(c4):输入账号和密码为空: (不输入账号和密码)
预期结果:账号或者密码不能为空
实际结果展示:
2.4 博客列表页面测试
(简介)在登录页面在对应的输入框输入正确的账号和密码后,会跳转到博客列表页面,可以看到当前登录的用户昵称和发布文章数量还有分类,列表区可以看到已发布博客文章信息(包括标题、时间、博客内容)等信息
(a)列表页展示:(如果已经发布了博客发布文章的数量不为0)
2.5 博客详情页面测试(点击博客列表页的查看全文进入)
(简介)博客详情页里面有当前登录用户的昵称,和发布文章的数量和分类的数量,可以看到可以发布的博客文章的(标题,发布博客的时间,和博客的内容)
(权限)如果查看的文章是当前用户自己发布的,那么当前用户对这篇文章的权限是:读,写,修改,删除等,如果查看的文章是其他用户发布的,那么当前用户对文章的权限只能是只读
(a)博客详情页面
预期效果:有用户信息,编辑和删除按钮存在,博客标题和内容存在
2.6 博客编辑页面测试
(简介)在博客列表页右上角点击”写博客“,即可进入博客编辑页面,此时可以进行新博客的写入操作。
(a)用户登录成功后会跳转到博客列表,点击右上角写博客,就会跳转到博客编辑页面
预期效果:博客编辑页面有(输入博客标题框,文本工具区,博客内容输入区,发布文章按钮)
实际效果展示:
2.6.1 发布博客测试
值得注意的是博客的标题或内容不能为空,否则会发布失败,弹出窗口提示
(c)博客发布成功实际图
预期效果:跳转回博客列表区,博客文章数量+1
实际效果展示:
2.6.2 删除博客测试
(简介)在博客列表页点击任意一篇发布的文章查看全文按钮,就可以进去到该篇博客的详情页,然后点击博客详情页里面的删除按钮,页面就会跳转到博客列表页,并且该片博客会被删除,博客数量-1
(a)在博客列表页点击查看全文,跳转到博客详情页
跳转到博客详情页,点击删除按钮
预期效果:当前博客文章被删除,且跳转回博客列表页,博客文章数量-1
实际效果展示:可以看到该博客已经消失在博客列表页了
2.5 博客退出功能测试
(简介)在博客列表页点击”退出“按钮之后,会跳转到博客登录界面,此时界面中的账号和密码输入框中的数据被清空,可以正常登录。
(a)点击右上角的注销按钮就可以退出博客
预期效果:退出到博客登录页面而且账号输入框的账号和密码输入框的密码都被清空
实际效果展示:
3. 使用Selenium进行Web自动化测试(Python)
(简介)想要进行Web自动化测试得先安装两个工具
1.selenium库:selenium是⼀个web⾃动化测试⼯具,selenium中提供了丰富的⽅法供给使⽤者进⾏web⾃动化测 试
2.webdriver-manager驱动:若通过安装驱动的⽅式来启动浏览器,每次浏览器更新后对应的驱动也需要更新,为了解决这个问 题,selenium中提供了驱动管理⼯具webdriver-manager,有了webdriver-manager⽆需⼿动安装浏 览器驱动,即使浏览器更新也不会影响⾃动化的执⾏,WebDriver Manager是⼀个开源的命令⾏⼯具,它可以⾃动下载和安装适⽤于不同浏览器的 WebDriver。通过使⽤WebDriverManager,我们可以确保浏览器驱动版本始终与浏览器版本保持⼀ 致,从⽽避免因版本不匹配⽽导致的各种问题
3.1新建项目
要进行自动化测试得先下载好pycharm和python环境哦,还有我这里使用的selenium版本是selenium4.0.0版本,webdriver-manager 版本为是4.0.1
1. 首先我们得点击pycharm进入到新建项目页面
2.选择你自己想要创建的路径
创建好一个新的项目后鼠标点击左上角的File选中里面的Steeings
出现这样一个页面,点击project:BlogautoTest里面的interpreter查看有没有刚才安装好的selenium库和webdriver-manager,(如果没有点击+号,手动搜索添加)
添加手动添加selenium库,选择版本4.0.0
注意添加的过程会需要一点时间,耐心等待一下
手动添加webdriver-manager版本4.0.1,操作同上
添加好后,我们可以在project:BlogautoTest里面的interpreter里面看到:如图:
3.2 参照测试用例,编写自动化脚本
3.2.1 创建驱动对象
首先我们有5个页面分别是:博客首页,博客登录页,博客列表页,博客详情页,博客编辑页,我们对这5个页面都要去创建驱动对象,通过驱动对象去get页面的URL去访问,就会出现这些部分的代码都是相同的,使用相同的代码有多次创建消耗性能的情况,我们可以把相同的部分提取出来放到一个python包里面,所以我们有了一个想法把创建驱动对象访问放到一个命名为common的python包,把测试不同页面的文件放到一个命名为test的python包
想法如图:
创建python包的方式:
在python包里面创建python文件:
创建完成图:
3.2.2 创建驱动对象步骤
真正的开始创建驱动对象了,首先在common包里面的Utils.py文件里面创建
1.一个Driver类,在类里面定义一个驱动对象成员,和
2. 两个构造函数,分别是对对象成员初始化的构造函数,和运行时截图的构造函数(为什么需要创建截图函数是为了在报错的时候查看问题更加方便)。
import os
import sys
import datetime
from selenium import webdriver
# from selenium.webdriver.support.wait import WebDriverWait
from webdriver_manager.microsoft import EdgeChromiumDriverManager
from selenium.webdriver.edge.service import Service
class Driver:
driver = ""
def __init__(self):
options = webdriver.EdgeOptions()
self.driver = webdriver.Edge(service=Service(EdgeChromiumDriverManager().install()),options=options)
#添加一个隐式等待,预防代码执行速度比页面渲染加载快,报错
self.driver.implicitly_wait(2)#隐式等待两秒,隐式等待的生命周期是整个查找过程
#截图函数
def GetScreeShot(self):
#首先在上一级路径创建一个文件夹,命名为:images+当天的年月日
#创建之前先看一下,文件夹是否存在
driname = datetime.datetime.now().strftime("%Y-%m-%d")
if not os.path.exists("../images/"+driname):
#如果不存在,就创建文件夹
os.mkdir("../images/"+driname)
#截图的图片名称要加上调用是哪个函数调用这个截图函数的
#图片名称:BlogLoginTest-2025-3-23-123409
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/"+driname+"/"+filename)
BlogDriver = Driver() #使用Driver类创建一个类驱动对象,其他函数想要使用这个驱动就得使用BlogDriver调用里面的驱动成员driver
创建一个运行文件,用来测试不同功能测试文件里面的测试函数(主函数的入口)
1.文件名为:RunTest.py
3.2.3 博客登录的自动化测试
①创建一个文件名为:BlogLoginTest.py,里面存在测试登录的函数(包括成功登录和异常登录)
②引入名为common的python包,包上common里面的Utils.py文件
③创建一个名为BlogLogin的类,把driver和url成员变量还有函数的实现方法定义在里面(登录成功为BlogSucTest,登录失败为BlogFailTest)
④重点注意清空输入框的内容后才能再次输入用户名及密码进行登录
⑤(测试内容):在这个自动化测试中主要是对页面是否正常打开,并且针对是否可以登录成功/登录失败进行测试。
⑥在RunTest.py里面主要函数调用的顺序,想要看到其他页面的正常效果必须先登录成功
#博客登录页面的BlogLoginTest测试文件
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
class BlogLogin:
driver = ""
url = ""
def __init__(self):
self.driver = BlogDriver.driver
self.url = "http://8.137.19.140:9090/blog_login.html"
self.driver.get(self.url)
def BlogSucText(self):#成功登录博客页面的函数的函数
#找到用户名框输入,正确的账号
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()
#成功登录后,查看一下用户昵称是否存在
#登录进去后来个登录成功的截图
BlogDriver.GetScreeShot()
#登录进去后检查一下用户的昵称是否存在
name = self.driver.find_element(By.CSS_SELECTOR,"body > div.container > div.left > div > h3").text
# 检查一下用户基本信息的文章是否存在
article = self.driver.find_element(By.CSS_SELECTOR,"body > div.container > div.left > div > div:nth-child(4) > span:nth-child(1)").text
# 检查一下用户基本信息的分类是否存在
classification = self.driver.find_element(By.CSS_SELECTOR,"body > div.container > div.left > div > div:nth-child(4) > span:nth-child(2)").text
print("BlogLogin:"+name)
print("BlogLogin:"+article)
print("BlogLogin:"+classification)
# self.driver.quit() #两个函数连用就得在登录失败的函数里面退出了
def BlogFailText(self):#错误登录博客的函数
#因为上面已经登录了,使用回退按钮,退回到登录页面
self.driver.back() #让浏览器后退,返回上一个页面
#找到用户命名输入框和密码输入框把里面的内容清空
self.driver.find_element(By.CSS_SELECTOR,"#username").clear()
self.driver.find_element(By.CSS_SELECTOR, "#password").clear()
#然后在输入错误的账号或者错误的密码
time.sleep(1)
self.driver.find_element(By.CSS_SELECTOR, "#username").send_keys("lisi")
self.driver.find_element(By.CSS_SELECTOR, "#password").send_keys("123")
time.sleep(1)
BlogDriver.GetScreeShot()
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
print(alert.text)
assert alert.text == "密码错误"
alert.accept() #点击同意按钮
添加:这个四个测试用例
#输入错误的账号,错误的密码 self.driver.find_element(By.CSS_SELECTOR, "#username").send_keys("lisi") self.driver.find_element(By.CSS_SELECTOR, "#password").send_keys("123") # 输入错误的账号,正常的密码 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, "#username").send_keys("zhangsan") self.driver.find_element(By.CSS_SELECTOR, "#password").send_keys("123") # 不输入账号,不输入密码 self.driver.find_element(By.CSS_SELECTOR, "#username").send_keys("lisi") self.driver.find_element(By.CSS_SELECTOR, "#password").send_keys("123")
#RunTest测试文件的内容
from tests import BlogLoginTest
from tests import BlogListTest
from tests import BlogDetailTest
from tests import BlogEditTest
from common.Utils import BlogDriver
if __name__ == "__main__":
blog_login_instance = BlogLoginTest.BlogLogin()
blog_login_instance.BlogSucText()
blog_login_instance.BlogFailText()
BlogDriver.driver.quit()
#可以看一下结果打印,是没有报错的
#再看一下截图函数执行的如何
可以看到截图函数,创建了一个images的文件夹,里面的图片命名也是符合
#图片名称:BlogLoginTest-2025-3-23-123409
filename=sys._getframe().f_back.f_code.co_name+""+datetime.datetime.now().strftime("%Y-%m-%d-%H%M%S")+".png"
3.2.4 博客列表页的自动化测试
①创建一个文件名为:BlogListTest.py,里面存在测试列表页的函数(包括成功登录状态下的列表页测试和未登录状态下的列表页测试)
②引入名为common的python包,包上common里面的Utils.py文件
③创建一个名为BlogList的类,把driver和url成员变量还有函数的实现方法定义在里面(成功登录测试的列表BlogLoginListTest,登录状态下退出登录函数QuitBlogLoginListTest,,未登录测试的列表页为NotBlogLoginListTest)
④重点注意清空输入框的内容后才能再次输入用户名及密码进行登录
⑤(测试内容):博客标题、博客发布的时间,博客内容、查看全文按钮,左边的用户基本信息等是否存在,以及"博客数量是否为0”
⑥在RunTest.py里面主要函数调用的顺序,想要看到其他页面的正常效果必须先登录成功
#博客列表页面的BlogListTest测试文件
import time
from selenium.webdriver.common.by import By
from common.Utils import BlogDriver
class BlogList:
driver = ""
url = ""
def __init__(self):
self.driver = BlogDriver.driver
self.url = "http://8.137.19.140:9090/blog_list.html"
self.driver.get(self.url)
def BlogLoginListTest(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.date")
#检查一下博客的内容是否存在
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")
#检查一下用户基本信息的文章是否存在
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)")
#检查一下博客数量是否为0,不为就就通过
Blognum = self.driver.find_element(By.CSS_SELECTOR,"body > div.container > div.left > div > div:nth-child(5) > span:nth-child(1)").text
print(Blognum)
assert Blognum != 0
BlogDriver.GetScreeShot()
# self.driver.quit()
def NotBlogLoginListTest(self): #未登录状态下
# # 找到用户命名输入框和密码输入框把里面的内容清空
# self.driver.find_element(By.CSS_SELECTOR, "#username").clear()
# self.driver.find_element(By.CSS_SELECTOR, "#password").clear()
self.driver.get("http://8.137.19.140:9090/blog_list.html")
time.sleep(2)
BlogDriver.GetScreeShot()
self.driver.find_element(By.CSS_SELECTOR, "body > div.container > div.right > div:nth-child(1) > div.title")
def QuitBlogLoginListText(self): # 登录博客状态下测试退出
#点击退出按钮
self.driver.find_element(By.CSS_SELECTOR, "body > div.nav > a:nth-child(6)").click()
BlogDriver.GetScreeShot()
#判断一下退出后的页面url和页面的标题
Quittitle = self.driver.title
QuitUrl = self.driver.current_url
print(Quittitle)
print(QuitUrl)
assert Quittitle == "博客登陆页"
assert QuitUrl == "http://8.137.19.140:9090/blog_login.html"
#判断一下账号输入框和密码输入框的内容是否为空
Quitusername = self.driver.find_element(By.CSS_SELECTOR,"#username").text
Quitpassword = self.driver.find_element(By.CSS_SELECTOR,"#password").text
print("Quitusername"+Quitusername)
print("Quitpassword"+Quitpassword)
assert Quitusername == ""
assert Quitpassword == ""
#RunTest测试文件的内容
if __name__ == "__main__":
blog_login_instance = BlogLoginTest.BlogLogin()
blog_login_instance.BlogSucText()
blog_list_instance = BlogListTest.BlogList()
#登录状态下测试博客列表页
blog_list_instance.BlogLoginListTest()
#退出博客登录
blog_list_instance.QuitBlogLoginListText()
#未登录状态下测试博客列表页
blog_list_instance.NotBlogLoginListTest()
BlogDriver.driver.quit()
#可以看一下结果打印,成功登录状态下测试列表页是没有报错的
#未成功登录状态下测试列表页是报错的,我们来看一下报错信息
报错信息大概说的是,没有找到元素,结果其实是符合我们预期的,因为我们已经退出登录了
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"body > div.container > div.right > div:nth-child(1) > div.title"}
(Session info: MicrosoftEdge=134.0.3124.83)
#再看一下截图函数,也是可以正常截到BlogListTest文件里面的测试函数运行时的图片的
3.2.4 博客详情页的自动化测试
①创建一个文件名为:BlogDetailTest.py,里面存在测试列表页的函数(包括成功登录状态下的详情页测试和未登录状态下的详情页测试)
②引入名为common的python包,包上common里面的Utils.py文件
③创建一个名为BlogDtail的类,把driver和url成员变量还有函数的实现方法定义在里面(成功登录状态下测试的列表BlogLoginDetailTest,成功登录状态下删除博客DeteleBlogLoginDetailTest,未登录状态下测试的列表页为NotBlogLoginDetailTest)
④重点注意清空输入框的内容后才能再次输入用户名及密码进行登录
⑤(测试内容):博客标题、博客发布的时间,博客内容、左边的用户基本信息,编辑和删除按钮等是否存在
⑥在RunTest.py里面主要函数调用的顺序,想要看到其他页面的正常效果必须先登录成功
#博客详情页面的BlogListTest测试文件
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
class BlogDetail:
driver = ""
url = ""
def __init__(self):
self.driver = BlogDriver.driver
#一篇博客的url
self.url = "http://8.137.19.140:9090/blog_detail.html?blogId=38068"
self.driver.get(self.url)
def BlogLoginDetailTest(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")
# 检查一下用户基本信息的昵称是否存在
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.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.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)")
#添加屏幕截图
BlogDriver.GetScreeShot()
time.sleep(2)
def DeleteBlogLoginDetailTest(self):
#点击第一篇博客删除按钮
BlogDriver.GetScreeShot()
self.driver.find_element(By.CSS_SELECTOR,"body > div.container > div.right > div > div.operating > button:nth-child(2)").click()
#点击删除按钮后会出现一个弹窗
wait = WebDriverWait(self.driver,2)
#检查弹窗是否出现
wait.until(EC.alert_is_present())
#找到弹窗
alert = self.driver.switch_to.alert
#判断一下弹窗里面的内容是否是确定删除?
actual = alert.text
print(actual)
assert actual == "确定删除?"
#点击确定删除按钮
alert.accept()
time.sleep(1)
BlogDriver.GetScreeShot()
#删除后判断一下是否返回到了博客列表页
time.sleep(1)
rettitle = self.driver.title
retUrl = self.driver.current_url
assert rettitle == "博客列表页"
assert retUrl == "http://8.137.19.140:9090/blog_list.html"
print("rettitle:"+rettitle)
print("retUrl:"+retUrl)
def NotBlogLoginDetailTest(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")
# 检查一下用户基本信息的昵称是否存在
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.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.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)")
# 添加屏幕截图
BlogDriver.GetScreeShot()
time.sleep(2)
#博客详情页面的RunTest测试文件
blog_login_instance = BlogLoginTest.BlogLogin()
blog_login_instance.BlogSucText()
blog_dateil_instance = BlogDetailTest.BlogDetail()
#测试登录状态下的详情页
blog_dateil_instance.BlogLoginDetailTest()
#测试登录状态下详情页删除第一篇文章
blog_dateil_instance.DeleteBlogLoginDetailTest()
#退出登录
blog_list_instance = BlogListTest.BlogList()
#退出博客登录
blog_list_instance.QuitBlogLoginListText()
blog_dateil_instance.NotBlogLoginDetailTest()
BlogDriver.driver.quit()
#可以看到删除前博客在列表页是存在的
#删除后博客已经在列表页消失了
#可以看到在登录状态下访问一篇博客的详情页,然后删除的信息是正确的,删除博客后返回到了博客列表页面
#报错显示也是正常的,因为我们已经退出了登录状态了,就查找不到博客详情页元素了
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"body > div.container > div.right > div > div.title"}
(Session info: MicrosoftEdge=134.0.3124.83)
3.2.5 博客编辑页的自动化测试
①创建一个文件名为:BlogLoginTest.py,里面存在测试登录的函数(包括成功登录和异常登录)
②引入名为common的python包,包上common里面的Utils.py文件
③创建一个名为BlogLogin的类,把driver和url成员变量还有函数的实现方法定义在里面(登录成功为BlogSucTest,登录失败为BlogFailTest)
④重点注意清空输入框的内容后才能再次输入用户名及密码进行登录
⑤(测试内容):在这个自动化测试中主要是对页面是否正常打开,并且针对是否可以登录成功/登录失败进行测试。
⑥在RunTest.py里面主要函数调用的顺序,想要看到其他页面的正常效果必须先登录成功
#博客编辑页面的BlogEditTest测试文件
import time
from selenium.webdriver.common.by import By
from 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 BlogLoginEditTest(self):
#找到标题输入框输入标题
self.driver.find_element(By.CSS_SELECTOR,"#title").send_keys("博客系统测试编辑页面")
#编辑区域的菜单栏是第三方插件,元素无法被选中,先不处理菜单栏
#博客编辑区本来就不为空
time.sleep(1)
BlogDriver.GetScreeShot()
#点击发布文章按钮
self.driver.find_element(By.CSS_SELECTOR,"#submit").click()
# 因为页面的跳转需要时间,代码执行的速度如果比页面渲染的速度快,就会导致找不到元素
time.sleep(1)
#发布文章后,会自动跳转到博客列表页,可以判断一下跳转后的url是否等于博客列表页的url
jumpURL = self.driver.current_url
print(jumpURL)
assert jumpURL == "http://8.137.19.140:9090/blog_list.html"
#判断一下博客列表页的文章标题是否是新发布的博客的给定的标题
# body > div.container > div.right > div: nth - child(33) > div.title,最近发布一篇文章是child(33)新发布的文章应该是child(34)
actual = self.driver.find_element(By.CSS_SELECTOR,"body > div.container > div.right > div:nth-child(34) > div.title").text
print(actual)
assert actual == "博客系统测试编辑页面"
def NotBlogLoginEditTest(self): #未登录下
# 未登录下是找不到标题输入框输入标题
self.driver.find_element(By.CSS_SELECTOR, "#title").send_keys("博客系统测试编辑页面")
#博客编辑页面的RunTest测试文件
#博客编辑页面的测试
blog_login_instance = BlogLoginTest.BlogLogin()
blog_login_instance.BlogSucText()
blog_edit_instance = BlogEditTest.BlogEdit()
blog_edit_instance.BlogLoginEditTest()
#然后调用退出博客函数
blog_list_instance = BlogListTest.BlogList()
blog_list_instance.QuitBlogLoginListText()
#再调用未登录状态下,去测试博客编辑页
blog_edit_instance.NotBlogLoginEditTest()
#可以看到在登录状态下,访问博客编辑页面的url,发布博客文章是没有问题的
#下面再来看一下,未登录状态下,访问博客编辑页面的url去查找编辑页面的元素的运行结果,是符合我们预期的,报错结果显示找不到编辑页面的编辑输入框
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"#title"}
(Session info: MicrosoftEdge=134.0.3124.83)
#在截图保存的文件夹中可以看到测试文件运行的时候截图的,运行出错的时候,可以用来对比
3.2.5 博客退出的的自动化测试
①在BlogList文件的BlogList类中构造函数,编写一个在登录状态下退出账号测试脚本
②这个界面中,主要是针对页面是否显示正常,在列表页点击“退出”(我这里的按钮名字是注销)按钮是否正常跳转到登录页
③在RuntTest.py中指定各个函数的执行顺序
#博客列表测试文件里面的退出函数代码
def QuitBlogLoginListText(self): # 登录博客状态下测试退出
#点击退出按钮
self.driver.find_element(By.CSS_SELECTOR, "body > div.nav > a:nth-child(6)").click()
BlogDriver.GetScreeShot()
#判断一下退出后的页面url和页面的标题
Quittitle = self.driver.title
QuitUrl = self.driver.current_url
print(Quittitle)
print(QuitUrl)
assert Quittitle == "博客登陆页"
assert QuitUrl == "http://8.137.19.140:9090/blog_login.html"
#判断一下账号输入框和密码输入框的内容是否为空
Quitusername = self.driver.find_element(By.CSS_SELECTOR,"#username").text
Quitpassword = self.driver.find_element(By.CSS_SELECTOR,"#password").text
print("Quitusername"+Quitusername)
print("Quitpassword"+Quitpassword)
assert Quitusername == "" #判断一下用户名输入框清空没有
assert Quitpassword == "" #判断一下密码输入框清空没有
#博客RunTest测试文件
#测试一下,在登录状态下,使用BlogListTest里面退出函数
blog_login_instance = BlogLoginTest.BlogLogin()
blog_login_instance.BlogSucText()
blog_list_instance = BlogListTest.BlogList()
#测试一下退出函数
blog_list_instance.QuitBlogLoginListText()
BlogDriver.driver.quit()
#看一下运行的结果是符合预期的
4.相比手动测试自动化测试的特点和优点
自动化测试的特点:当我们设计好项目的测试用例后,然后在Pycharm里面利用selenium库里面很多自动化测试方法给我们编写自动化测试脚本,能够执行更加繁琐的测试用例和在一定程度上解放测试人员,避免了重复繁琐的测试过程,让测试人员有更多的精力去设计更详细的测试用例和编写性能更高的测试脚本,提高测试结果的可行度,但是重点注意的是,不是编写了自动化测试脚本后就完全不用管了,要检查和维护这个自动化测试化脚本。自动化测试的成本包括自动测试开发成本、自动测试运行成本、自动测试维护成本和其他相关任务带来的成本,以及软件的修改带来的测试脚本部分或全部修改所增加的测试维护的开销。
自动化测试的优点:
①把测试不同页面和不同功能分为不同的测试文件,提高的代码的可读性,检查的时间也方便查找出不同模块出现问题的位置
②把创建驱动放到一个python里面的python中,避免重复创建驱动的消耗,提高性能和节约空间和时间
③当代码的加载速度比页面的渲染速度快的时候,人力测试要盯着页面,而自动化测试可以使用显示等待和隐式等待可以在规定时间内等待页面加载出来,最好不要使用强制等待(消耗的时间太多)
④可以在每个测试函数调用的时候,调用在驱动对象类里面创建截图函数,来记录函数运行时的页面,当出现报错的时候可以在截图中查找问题
5.使用jmeter对博客系统进行性能测试
这是在开发者工具里面的页面
在使用jmeter进行性能测试之前,我们通常会在postman里面进行一些简单的测试
登录页的data可以理解为用户的登录凭证
5.1 在jmeter里面测试登录页面接口
5.1.1 测试博客登录页接口
登录接口测试通过,在查看结果树中查看
5.1.2 测试博客列表页接口
这里说一下,同一个系统中协议,服务器名称或IP,端口号是不会发生变化的,所以添加一个HTTP请求默认值,其他页面不用配置3个选项,运行时会自动去HTTP请求默认值里面取
可是我们运行的时候发现报错了是怎么回事呢?
因为我们的请求头里面有一个用户的登录凭证,没有加上
原来是用户的登录凭证为空? 其实在postman里面可以看到说的是用户登录凭证为空
那么怎么提取用户的登录凭证呢?
使用到json提取器
然后添加一个HTTP信息头管理器
所有准备工作做好后,在来运行,就可以运行成功了:状态码为:success
5.1.3 测试博客用户个人信息接口
postman里面测试通过
这里使用json提取器要注意的是:json提取器会重复提取data,得把json提取器放到登录页的子路径下,只让他提取登录页的data
在查看结果树里面看到运行结果:
5.1.4 测试博客详情页接口
postman上面可以跑通
随便找了一个博客的路径
运行一下,在查看结果树上面看看:运行通过
可是问题是:我博客的id不能写死呀,怎么做呢?现在又可以使用json提取器了,把json提取器放到博客列表页里面提取博客文章的id
在查看结果树里面可以看到提取到了博客id
5.1.4 测试添加博客接口
postman中可以成功添加一篇博客
来看看postman中添加博客的结果
那我们在jmeter里面也来添加博客:
这里发布博客其实是失败的,因为状态码是fail,然后错误数据也返回了
那我们可以看看请求头有啥不一样,为什么开发者工具上面和postman都可以发布成功
我们可以看到开发者工具上面和postman的content-Type:是application/json,而jmeter的content-Type:是text/plain
那我们知道了,我们给添加博客的HTTP请求单独添加一个一个信息头管理器:
不能添加到全局属性的HTTP信息头管理器哦,因为登录页面的请求头里面也有content-Type:而且是不一样的,不然把登录页面的content-Type改了,登录凭证没了,全都是不通过的
现在可以看到,添加博客才是成功的
5.1.4 测试添加JSON断言
为什么要添加JSON断言呢?因为我们开启多线程(虚拟用户的数量增加)我们不可能一个一个去查看结果的反馈是否符合我们的预期
可以看到添加了JSON断言后,测试还是可以通过的
我简单讲一下JSON断言的细节:正则匹配的语法:https://www.runoob.com/regexp/regexp-syntax.html
我们可以点击在右上角的黄色小感叹号:查看线程的进度
添加事务:把登陆页面和用户个人信息看成一个事务
5.1.5 添加CSV数据文件设置
以登陆接⼝为例,当我们执⾏登陆接⼝的性能测试时,⼿动配置了⽤⼾名和密码为固定的username和 password,这样子我们的账号密码就手动写死了,然⽽实际使⽤中不可能只有⼀个⽤⼾登陆,为了模拟更真实的登录环境,我们需要提供更 多的⽤⼾username和password来实现登录操作
在查看结果树里面查看运行结果:可以看到登录了两个不同的用户
5.1.6 添加HTTP cookie 管理器
那cookie到底是什么呢?Cookie 是一种在客户端(通常是浏览器)和服务器之间传递的小型文本文件,用于存储用户会话信息、偏好设置或其他数据。它在 Web 开发和网络应用中广泛使用,主要用于实现用户认证、会话管理、个性化体验等功能。
我们可以在postman上面看到有cookie和没有cookie的情况,也可以把cookie理解为登录凭证
那我们可以在jmeter里面添加HTTP cookie 管理器(如果有cookie信息会自动获取的)
第二个登录的cookie信息是从第一个post请求的响应头里面来的
5.1.6 真的开始性能测试了
先添加一些小插件:
对这些小插件的解释: 为什么要添加梯度压测线程组呢?因为我们的线程数量是慢慢增加的,比如我们要测试服务器的最大承载能力:是先加100的线程,观察一段时间,服务器没有问题,再继续往上增加线程的数量,一上来就给很大,可以直接给服务器干奔溃了
然后看一下:梯度压测线程组
对图片解读:
This group will start:启动多少个线程,同线程组中的线程数
First, wait for:等待多少秒才开始压测,⼀般默认为0
Thenstart:⼀开始有多少个线程数,⼀般默认为0
Next,add:下⼀次增加多少个线程数
threads every:当前运⾏多⻓时间后再次启动线程,即每⼀次线程启动完成之后的的持续时间;
using ramp-up:启动线程的时间;若设置为5秒,表⽰每次启动线程都持续5秒
thenhold loadfor:线程全部启动完之后持续运⾏多⻓时间
finally,stop/threadsevery:多⻓时间释放多少个线程;若设置为5个和1秒,表⽰持续负载结束之后 每1秒钟释放5个线程
5.1.7 对测试结果解读:
先看一下活跃的线程数量:
响应时间:特别注意一下圈起来那里,都快结束了响应时间还这么长,说明退出的时候没有得到响应一直退出不了,我这个进程发送了请求但是服务器一直没有给到反馈
在聚合报告里面也可以看到:列表页的执行时间超出其他页面很多,说明是列表页的一个进程出了问题
吞吐量:
erm其实响应时间和吞吐量是有一定关系的:响应时间增加了,服务器就有了压力,这个时间服务器处理的并发数量是有限的,所以吞吐量就降低了
我们从图片直接结果的图片上面也可以看到响应时间和吞吐量的关系:响应时间高,吞吐量就低
5.1.8 生成性能测试报告
JMeter测试报告是⼀个全⾯⽽详细的⽂档,它提供了关于测试执⾏结果的详细信息,帮助⽤⼾全⾯评 估系统的性能并进⾏性能优化。
⽣成性能测试报告的命令:在终端执行命令
Jmeter -n -t 脚本⽂件 -l ⽇志⽂件 -e -o ⽬录
-n : ⽆图形化运⾏
-t : 被运⾏的脚本
-l : 将运⾏信息写⼊⽇志⽂件,后缀为 jtl 的⽇志⽂件
-e : ⽣成测试报告
-o : 指定报告输出⽬录
Gitee里面好像:打开是代码我截图出来给你们看
活跃进程数量:
吞吐量:
响应时间:
6.完整的自动化测试代码链接
我的Gitee仓库:测试开发: 测试开发用例的代码(https://gitee.com/im-just-a-pig/test-development)
我把性能测试报告放到我的gitee上面: