个人博客自动化测试报告
一、项目背景
背景:当在学习一项技能的时候,我们总会习惯通过博客来记录所学的知识点,方便后期遗忘时随时查看和快速复习。本次开发的Web网站程序便是为了更加轻量和方便地记录自己的学习笔记
概述:一个Web网站程序,可以随时随地查看自己和其他用户发布的博客,也可以自己注册登录后发布属于自己的博客
二、功能测试
2.1、根据功能编写自动化测试用例
编写测试用例一般从,功能测试、界面测试、性能测试、兼容性测试、安全性测试、易用性测试等方面编写,但个人博客是web网页,所以我们主要从功能方面测试。
个人博客主要有登录、博客主页、博客列表、博客编写和发布,退出登录等功能。
测试用例如下
2.2、使用Selenium进行Web自动化测试(Python)
2.2.1、创建公共类Utils
- 创建驱动、保存现场截图
- 注意:在保存现场截图的时候命名是按时间来进行文件夹的划分,然后图片的名称要体现出测试类的类名,方便进行问题的追溯。
- 注意文件名的动态获取,注意时间格式的设置。
import datetime
import os
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()
#添加页面加载策略
options.page_load_strategy = 'eager'
self.driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()),options=options)
# 添加隐式等待
# 有些操作执行完成之后会发生页面的跳转,页面跳转需要加载时间,
可能会出现代码执行的速度比页面渲染的速度要快,导致元素找不到,因此可以添加等待
self.driver.implicitly_wait(2)
def getScreenShot(self):
#创建屏幕截图
#图片文件名称:./2024-08-09-122332.png
dirName = datetime.datetime.now().strftime("%Y-%m-%d")
#判断dirName文件夹是否存在,如果不存在则创建文件夹
if not os.path.exists("../images/"+dirName):
os.mkdir("../images/"+dirName)
#2024-0809-122332.png
#图片文件路径:../images/调用方法-2024-08-09-122332.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.2.2、登录页面测试
- 创建驱动,并打开页面
- 测试页面是否正常打开
- 测试正常登录:多参数测试
- 测试异常登录:按照异常用例测试
- 注意测试的顺序,使用Order注解指定,否则可能会因为执行顺序不对导致测试失败
- 注意清空内容后才能再次输入用户名以及密码
#测试博客登录页面
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.Until import BlogDriver
class BlogLogin:
url = ""
driver = ""
#构造函数
def __init__(self):
self.url = "http://127.0.0.1:8080/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("admin")
self.driver.find_element(By.CSS_SELECTOR,"#password").send_keys("123")
# time.sleep(2)
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").click()
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("admin")
self.driver.find_element(By.CSS_SELECTOR,"#password").send_keys("1234")
self.driver.find_element(By.CSS_SELECTOR,"#submit").click()
#检查是否登录失败
#使用显示等待中的alert_is_present
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("admina")
self.driver.find_element(By.CSS_SELECTOR,"#password").send_keys("123")
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()
# alert.dismiss()
#添加错误的账号和错误的密码
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("admins")
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())
assert alert.text == "用户名或密码错误"
# alert.accept()#点击确认
alert.dismiss()#点击取消
# 添加屏幕截图,查看运行时是否出现问题
BlogDriver.getScreenShot()
2.2.3、博客首页测试
- 创建驱动,并打开页面
- 测试页面是否正常打开
- 测试登录状态下:显示是否正常,按钮是否可用
- 测试未登录:是否正常提示,是否跳转
#博客首页测试用例
from selenium.webdriver.common.by import By
from common.Until import BlogDriver
from bs4 import BeautifulSoup
import requests
# import pandas as pd
class BlogList:
url = ""
driver = ""
def __init__(self):
self.url = "http://127.0.0.1:8080/blog_list.html"
self.driver = BlogDriver.driver
self.driver.get(self.url)
#测试首页(登录状态下)
def LoginListTest(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.title")
#检查按钮是否存在
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")
#检查博客数量是否为0
text = self.driver.find_element(By.CSS_SELECTOR,"#article-count").text
print(text)
# 断言 -- 如果元素不为0,即测试通过
assert text != "0"
#添加屏幕截图
BlogDriver.getScreenShot()
# 测试首页(未登录状态下)
def NotLoginListTest(self):
self.driver.back()
self.driver.find_element(By.CSS_SELECTOR,"#userName").clear()
self.driver.find_element(By.CSS_SELECTOR,"#password").clear()
#如果在未登录的情况下访问博客列表中的博客标题会出现报错,访问不到该元素
text = self.driver.find_element("body > div.container > div.right > div:nth-child(1) > div.title").text()
2.2.4、博客详请也测试
- 测试详情页的正确打开:有blogId和没有blogId两种情况
- 测试“查看全文”按钮是否可用,注意比较的是时间
- 一定要注意导航回到列表页的操作
from selenium.webdriver.common.by import By
from common.Until import BlogDriver
#博客详情页测试用例
class BlogDetail:
url = ""
driver = ""
def __init__(self):
self.url = "http://127.0.0.1:8080/blog_detail.html?blogId=3556"
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.getScreenShot()
2.25、博客编辑和提交测试
- 测试“写文章按钮”是否可以正确使用
- 测试博客是否可以正常发布:元素齐全 or 部分元素
- 测试编辑也是否能正常跳转
- 博客内容用了第三方插件,无法定位,因为内容输入框默认不为空,所以暂不处理
- 这里测试发布成功与否,因为页面加载缓慢所以需要等待
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.Until import BlogDriver
#博客编辑页测试用例
class BlogEdit:
url = ""
driver = ""
def __init__(self):
self.url = "http://127.0.0.1:8080/blog_edit.html"
self.driver = BlogDriver.driver
self.driver.get(self.url)
#正确发布博客测试(登录状态下)
def EditTestByLog(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(19)").click()
# 直接点击发布博客
self.driver.find_element(By.CSS_SELECTOR,"#submit").click()
#点击发布博客之后出现页面的跳转, 页面跳转需要加载时间,可能会出现代码执行的速度比页面渲染的速度要快,导致元素找不到,因此可以添加等待
#显示等待
# wait = WebDriverWait(self.driver,10).until(EC.visibility_of_element_located((By.CSS_SELECTOR,"body > div.container > div.right > div:nth-child(1) > div.title")))
#断言:第一篇博客的标题是否为给定的标题
actual = self.driver.find_element(By.CSS_SELECTOR,"body > div.container > div.right > div:nth-child(1) > div.title").text
assert actual == "自动化测试用例"
#添加屏幕截图查看博客是否发布成功
BlogDriver.getScreenShot()
三、小结
- 一定要关注测试用例的执行顺序问题
- 对于页面的检查一定要到位,如检查元素是否存在确保页面的正确性。
- 注意多参数测试的页面导航问题。
- 注意:一定要关注执行顺序!
- 因为列表页等的测试是需要在登录成功后才能抵达的,所以在进行登录页面测试的最后一步应该是登录成功的状态,这样子是为了确保列表页等能够正确进入测试。【并不是绝对,但是需要进行关注】。
- 驱动关闭的位置要注意,只有最后一个用例结束之后才进行关闭。
- 为了把所有的用例的执行结果保存下来,方便后续查错或查看,也就是保存现场,此时就需要直接在公共类中进行该方法的定义。
- 注意屏幕截图保存的方式:动态时间戳并进行时间格式化,然后期望按照某种维度(天、周)以文件夹的方式进行保存。
- 获取元素的时候建议获取固定的元素,如时间、标题等;内容不建议获取,因为是动态的。然后元素的路径是不可变的,所以可以使用xpath来进行元素的定位。
- 可以适当关注用例执行时间,如果时间过长就需要考虑是我们自己写的测试用例的问题还是程序真的有性能问题呢。
- 为了避免遗漏or遗忘驱动释放的位置,可以单独写一个类来存放驱动释放,然后直接放到套件测试类的最后就行。
- 测试用例并不是越多越好
难点:注意测试执行的顺序,文本框输入一定要检查,对于元素的定位一定要查看。