论坛系统测试报告
1.项目背景
本项目是基于 SSM 框架(Spring、Spring MVC、MyBatis) 开发的 论坛系统,包括 用户注册、登录、帖子发布、编辑、删除、查看 等功能,同时提供 帖子列表页和详情页 供用户浏览论坛内容。
用户登录后可以 查看自己和其他用户的帖子,并通过系统 记录帖子发布时间、标题、作者信息。论坛支持 用户评论、私信交流、帖子点赞等社交互动功能,提升用户体验。
为了确保系统的稳定性和功能完整性,项目采用 Selenium 自动化测试 进行功能验证,测试内容涵盖:
-
用户注册与登录:测试不同输入情况下的账号验证逻辑
-
帖子列表展示:确保帖子加载、排序和分页功能正常
-
用户信息校验:验证用户个人资料、修改信息的功能
-
帖子管理:测试帖子发布、编辑、删除是否符合预期
-
帖子详情页:检查帖子的内容是否正确加载,包括评论、点赞等互动功能
-
搜索功能:验证用户输入关键词后,搜索结果是否匹配
本项目通过自动化测试覆盖核心功能,确保论坛系统在不同用户操作和高并发场景下的稳定性和可靠性,同时减少人工测试成本,提高测试效率。
2.测试内容
2.1.功能测试
2.1.1.编写测试用例
2.1.2.执行测试用例
登录测试
- (a)界面展示
- (b)输入正确的账号和密码(如:账号 qiyu,密码 123456)
- 预期结果:成功登录,并跳转至主页。
- 实际结果:正常
- (c)输入错误的账号和密码(如:账号 q,密码 1234)
- 预期结果:登录失败,跳出提示
- 实际结果:正常
- (d)只输入密码(如:密码 123456)
- 预期结果:登录失败,提示密码不可为空
- 实际结果:正常
- (b)只输入账号(如:账号 qiyu)
- 预期结果:登录失败,提示账号不可为空
- 实际结果:正常
- (e)不输入账号和密码
- 预期结果:登录失败,提示账号密码不可为空
- 实际结果:显示正确
个人中心页测试
- (a)界面展示
- (b)测试各各输入框
- 预期结果:能正常输入修改
- 实际结果:头像可上传但无法修改,其他正常
帖子编辑页测试
- (a)界面展示
- (b)测试板块
- 预期结果:默认是java和能正常修改
- 实际结果:正常
- (c)测试标题框和文字框能否正常输入修改
- 预期结果:能否正常输入修改
- 实际结果:修改正常
- (d)测试能否正常发布
- 预期结果:发布成功
- 实际结果:
帖子详细页测试
- (a)界面展示
- (b)测试菜单栏搜索框
- 预期结果:正常输入,正常搜索
- 实际结果:正常输入,但搜索功能无法使用
- (c)测试菜单栏日间夜间切换按钮
- 预期结果:可正常切换
- 实际结果:正常,但会自动切回主页
- (d)测试菜单栏信息按钮
- 预期结果:可弹出消息页
- 实际结果:正常
- (e)测试个人信息
- 预期结果:能与登录用户对应
- 实际结果:对应
- (f)测试点赞按钮
- 预期结果:弹窗提示,点赞数量增加
- 实际结果:成功
- (g)测试评论区
- 预期结果:可发送评论
- 实际结果:正常发送,但在夜间模式输入框输入的文字不可见
- (h)测试发私信按钮
- 预期结果:可弹出回复私信页,可正常发送
- 实际结果:正常
回复私信页测试
- (a)界面展示
- (b)测试输入框
- 预期结果:能正常输入修改
- 实际结果:正常
- (c)测试能否正常发送
- 预期结果:可正常发送
- 实际结果:正常
首页测试
- (a)界面展示
- (b)测试各板块跳转
- 预期结果:可正常跳转
- 实际结果:可正常跳转,但缺失部分板块名称
- (c)测试帖子列表
- 预期结果:点击进入帖子详细页
- 实际结果:正常
我的帖子页测试
- (a)界面展示
- (b)检查页面信息
- 预期结果:能与登录用户对应
- 实际结果:可对应
注册页测试
- (a)界面展示
- (b)正常注册测试
- 预期结果:注册完跳转至登录页
- 实际结果:正常
- (c)异常注册测试
- 预期结果:未输入或两次密码不一致时提示
- 实际结果:正常
2.2 使用 Selenium 进行 Web 自动化测试(Python)
2.2.1 安装 WebDriverManager 和 Selenium
WebDriverManager 是用于管理 Web 驱动程序的工具,在进行 Selenium 测试时,浏览器需要对应的 WebDriver 进行控制和操作。WebDriverManager 能够自动检测本地浏览器版本并下载匹配的驱动程序(如 ChromeDriver、FirefoxDriver 等),避免手动下载和配置的繁琐过程,提高测试效率和稳定性。
2.2.2 创建测试项目
-
在项目中打开 File → Settings,进入设置界面。
-
在“Project: 当前项目名”下,检查是否已安装
selenium
和webdriver-manager
依赖。 -
若未安装,可使用以下命令进行安装:
pip install selenium webdriver-manager
公共工具(Utils.py)
测试目标
-
提供
WebDriver
实例,供各测试脚本调用。 -
统一管理浏览器驱动,支持截图功能。
测试步骤
-
在
Utils.py
中定义BlogDriver
类,初始化Edge
浏览器驱动。 -
提供
get_driver()
方法,返回WebDriver
实例。 -
提供
screenshot()
方法,支持测试过程中截图。
import datetime
import os
import sys
from webdriver_manager.microsoft import EdgeChromiumDriverManager
from selenium import webdriver
from selenium.webdriver.edge.service import Serviceclass Driver:driver = Nonedef __init__(self):"""初始化WebDriver并启动浏览器"""options = webdriver.EdgeOptions()options.page_load_strategy = 'eager'# options.add_argument('-headless') # 启动无界面模式edge_driver_path = EdgeChromiumDriverManager().install()self.driver = webdriver.Edge(service=Service(edge_driver_path), options=options)def getScreenShot(self):"""保存当前页面的截图到指定目录"""dirname = datetime.datetime.now().strftime('%Y-%m-%d')screenshot_dir = os.path.join(os.path.dirname(os.getcwd()), 'images', dirname)# 如果截图目录不存在,则创建if not os.path.exists(screenshot_dir):os.makedirs(screenshot_dir)# 根据方法名和时间戳生成唯一的文件名filename = sys._getframe().f_back.f_code.co_name + "-" + datetime.datetime.now().strftime('%Y-%m-%d-%H%M%S') + ".png"# 保存截图screenshot_path = os.path.join(screenshot_dir, filename)self.driver.save_screenshot(screenshot_path)# 创建BlogDriver实例
BlogDriver = Driver()
登录页自动化测试(Login.py)
测试目标
-
确保用户登录功能正常,包括不同输入组合的处理逻辑。
测试步骤
-
创建
Login.py
,引入Utils.py
及相关依赖。 -
定义
Login
类,管理登录页面的测试用例。 -
实现以下测试方法:
-
正确登录测试:使用正确的用户名和密码进行登录,并验证登录成功。
-
用户名/密码为空测试:测试用户名或密码为空时的登录提示。
-
用户名/密码错误测试:输入错误的用户名或密码,检查是否拒绝登录。
-
页面跳转测试:确保登录成功后跳转到主页。
-
执行方式
-
在
RunTest.py
中调用Login
类执行测试。import time from common.Utils import Driver from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.alert import Alertclass Login:url = ''driver = ''def __init__(self):# 初始化URL和driver,打开登录页面self.url = 'http://127.0.0.1:9580/sign-in.html'self.driver = Driver.driverself.driver.get(self.url)def _login(self, username, password):# 等待提交按钮可点击,输入用户名和密码,并点击登录按钮WebDriverWait(self.driver,10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#submit')))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(username)self.driver.find_element(By.CSS_SELECTOR, "#password").send_keys(password)self.driver.find_element(By.CSS_SELECTOR,'#submit').click()def _verify_login_success(self):"""验证用户是否成功登录"""try:# 等待文章列表标题元素出现来验证是否登录成功WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#article_list_board_title')))except:pass# 确认登录后页面中存在文章列表标题assert self.driver.find_element(By.CSS_SELECTOR, '#article_list_board_title') is not Nonedef login_suc_test1(self):# 测试用户1的登录self._login('qiyu','123456')self._verify_login_success()Driver.getScreenShot()self.driver.back()def login_suc_test2(self):# 测试用户2的登录self._login('zhangsan','1234')self._verify_login_success()self.driver.back()def check_error_alert(self):# 检查错误提示是否出现try:WebDriverWait(self.driver,5).until(EC.presence_of_element_located((By.CSS_SELECTOR,'body > div.jq-toast-wrap.bottom-right > div')))except:pass# 验证是否有错误提示assert self.driver.find_element(By.CSS_SELECTOR,'body > div.jq-toast-wrap.bottom-right > div')def check_error_appear(self, username, password):# 验证错误提示是否在用户名或密码为空时出现if username == 'empty':try:WebDriverWait(self.driver, 5).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#signInForm > div.mb-3 > div')))except:pass# 验证用户名为空时是否出现错误提示assert self.driver.find_element(By.CSS_SELECTOR, '#signInForm > div.mb-3 > div')if password == 'empty':try:WebDriverWait(self.driver, 5).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#signInForm > div.mb-2 > div > div')))except:pass# 验证密码为空时是否出现错误提示assert self.driver.find_element(By.CSS_SELECTOR, '#signInForm > div.mb-2 > div > div')def test_login_empty_username_empty_password(self):"""测试用户名和密码为空时的登录行为"""self._login('', '')self.check_error_appear('empty','empty')self.driver.back()def test_login_empty_username_valid_password(self):"""测试用户名为空,密码有效时的登录行为"""self._login('', '1234')self.check_error_appear('empty','')self.driver.back()def test_login_empty_username_invalid_password(self):"""测试用户名为空,密码无效时的登录行为"""self._login('', '123')self.check_error_appear('empty','')self.driver.back()def test_login_invalid_username_empty_password(self):"""测试用户名无效,密码为空时的登录行为"""self._login('123', '')self.check_error_appear('','empty')self.driver.back()def test_login_valid_username_empty_password(self):"""测试用户名有效,密码为空时的登录行为"""self._login('zhangsan', '')self.check_error_appear('','empty')self.driver.back()def test_login_valid_username_invalid_password(self):"""测试用户名有效,密码无效时的登录行为"""self._login('zhangsan', '123')self.check_error_alert()self.driver.back()def test_login_invalid_username_valid_password(self):"""测试用户名无效,密码有效时的登录行为"""self._login('12312', '12334')self.check_error_alert()self.driver.back()def test_login_invalid_username_invalid_password(self):"""测试用户名无效,密码无效时的登录行为"""self._login('123', '123')self.check_error_alert()self.driver.back()
注册页自动化测试(Register.py)
测试目标
-
确保用户注册功能正常,包括不同输入组合的处理逻辑。
测试步骤
-
创建
Register.py
,引入Utils.py
及相关依赖。 -
定义
Register
类,管理注册页面的测试用例。 -
实现以下测试方法:
-
正确注册测试:填写完整有效信息,并检查注册成功后跳转到登录页。
-
用户名/密码/昵称为空测试:测试部分字段为空时,系统是否提示错误。
-
密码不匹配测试:测试密码与确认密码不一致的情况。
-
未勾选用户协议测试:检查未勾选协议时,是否阻止注册。
-
执行方式
-
在
RunTest.py
中调用Register
类执行测试。import time import random from common.Utils import Driver from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as ECclass Register:driver = ''url = ''def __init__(self):self.url = 'http://127.0.0.1:9580/sign-up.html'self.driver = Driver.driverself.driver.get(self.url)def test_valid_inputs_agree_terms(self):"""测试:所有输入均有效,并且同意条款"""random_name = random.randint(100000, 999999)random_nickname = random.randint(100000, 999999)random_password = random.randint(100000, 999999)# 等待输入框加载WebDriverWait(self.driver,10).until(EC.presence_of_element_located((By.CSS_SELECTOR,'#username')))# 填写表单self.driver.find_element(By.CSS_SELECTOR, '#username').send_keys(random_name)self.driver.find_element(By.CSS_SELECTOR, '#nickname').send_keys(random_nickname)self.driver.find_element(By.CSS_SELECTOR, '#password').send_keys(random_password)self.driver.find_element(By.CSS_SELECTOR, '#passwordRepeat').send_keys(random_password)self.driver.find_element(By.CSS_SELECTOR, '#policy').click()self.driver.find_element(By.CSS_SELECTOR,'#submit').click()# 等待页面跳转WebDriverWait(self.driver,10).until(EC.presence_of_element_located((By.CSS_SELECTOR,'body > div > div > div > div:nth-child(1) > div > div.card.card-md > div > h2')))# 确认跳转到 "用户登录" 页面assert self.driver.find_element(By.CSS_SELECTOR,'body > div > div > div > div:nth-child(1) > div > div.card.card-md > div > h2').text == '用户登录'# 登录测试self.driver.find_element(By.CSS_SELECTOR,'#username').send_keys(random_name)self.driver.find_element(By.CSS_SELECTOR,'#password').send_keys(random_password)self.driver.find_element(By.CSS_SELECTOR,'#submit').click()try:WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR,'#bit-forum-content > div.page-header.d-print-none > div > div > div > h2').text == "首页")except:passassert self.driver.find_element(By.CSS_SELECTOR,'#bit-forum-content > div.page-header.d-print-none > div > div > div > h2').text == '首页'def test_valid_username_empty_others_disagree_terms(self):"""测试:用户名有效,其他字段为空,且不同意条款"""WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#username')))self.driver.find_element(By.CSS_SELECTOR, '#username').send_keys('random_name')# 点击提交按钮WebDriverWait(self.driver,10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#submit')))self.driver.find_element(By.CSS_SELECTOR, '#submit').click()# 检查错误提示WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, '#signUpForm > div > div:nth-child(3) > div')))WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, '#signUpForm > div > div:nth-child(4) > div')))WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, '#signUpForm > div > div:nth-child(5) > div')))assert "is-invalid" in self.driver.find_element(By.ID, "policy").get_attribute("class")def test_empty_username_valid_nickname_mixed_passwords_disagree_terms(self):"""测试:用户名为空,昵称有效,密码和确认密码不匹配,且不同意条款"""WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#nickname')))self.driver.find_element(By.CSS_SELECTOR, '#nickname').send_keys('random_nickname')WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#password')))self.driver.find_element(By.CSS_SELECTOR, '#password').send_keys('random_password')WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#passwordRepeat')))self.driver.find_element(By.CSS_SELECTOR, '#passwordRepeat').send_keys('random_passwordRepeat')WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#submit')))self.driver.find_element(By.CSS_SELECTOR, '#submit').click()# 等待错误信息WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, '#signUpForm > div > div:nth-child(2) > div')))WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, '#signUpForm > div > div:nth-child(5) > div')))assert "is-invalid" in self.driver.find_element(By.ID, "policy").get_attribute("class")def test_empty_username_nickname_valid_password_agree_terms(self):"""测试:用户名和昵称为空,密码有效,且同意条款"""WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#password')))self.driver.find_element(By.CSS_SELECTOR, '#password').send_keys('random_password')WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#passwordRepeat')))self.driver.find_element(By.CSS_SELECTOR, '#passwordRepeat').send_keys('random_password')self.driver.find_element(By.CSS_SELECTOR, '#policy').click()WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#submit')))self.driver.find_element(By.CSS_SELECTOR, '#submit').click()# 检查是否出现错误信息WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, '#signUpForm > div > div:nth-child(2) > div')))WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, '#signUpForm > div > div:nth-child(3) > div')))assert "is-valid" in self.driver.find_element(By.ID, "policy").get_attribute("class")def test_valid_inputs_missing_confirm_password_disagree_terms(self):"""测试:所有输入有效,但缺少确认密码,且不同意条款"""WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#username')))self.driver.find_element(By.CSS_SELECTOR, '#username').send_keys('random_name')WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#nickname')))self.driver.find_element(By.CSS_SELECTOR, '#nickname').send_keys('random_nickname')WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#password')))self.driver.find_element(By.CSS_SELECTOR, '#password').send_keys('random_password')WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#submit')))self.driver.find_element(By.CSS_SELECTOR, '#submit').click()# 检查是否出现错误信息WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, '#signUpForm > div > div:nth-child(5) > div')))assert "is-invalid" in self.driver.find_element(By.ID, "policy").get_attribute("class")def test_valid_username_empty_nickname_password_confirmed_agree_terms(self):"""测试:用户名有效,昵称为空,密码和确认密码匹配,且同意条款"""WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#username')))self.driver.find_element(By.CSS_SELECTOR, '#username').send_keys('random_name')WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#password')))self.driver.find_element(By.CSS_SELECTOR, '#password').send_keys('random_password')WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#passwordRepeat')))self.driver.find_element(By.CSS_SELECTOR, '#passwordRepeat').send_keys('random_password')self.driver.find_element(By.CSS_SELECTOR, '#policy').click()WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#submit')))self.driver.find_element(By.CSS_SELECTOR, '#submit').click()# 检查是否出现错误信息WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, '#signUpForm > div > div:nth-child(3) > div')))assert "is-valid" in self.driver.find_element(By.ID, "policy").get_attribute("class")def test_invalid_inputs_disagree_terms(self):"""测试:所有输入均无效,并且不同意条款"""WebDriverWait(self.driver,10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#submit')))self.driver.find_element(By.CSS_SELECTOR, '#submit').click()# 确保所有字段都显示错误WebDriverWait(self.driver,10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, '#signUpForm > div > div:nth-child(2) > div')))WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, '#signUpForm > div > div:nth-child(3) > div')))WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, '#signUpForm > div > div:nth-child(4) > div')))WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, '#signUpForm > div > div:nth-child(5) > div')))assert "is-invalid" in self.driver.find_element(By.ID, "policy").get_attribute("class")
个人主页自动化测试(PersonalHomepage.py)
测试目标
-
确保个人主页各功能正常,包括修改个人信息、头像、密码等。
测试步骤
-
创建
PersonalHomepage.py
,引入Utils.py
及相关依赖。 -
定义
PersonalHomepage
类,管理个人主页的测试用例。 -
实现以下测试方法:
-
切换页面测试:测试不同版块的切换功能,确保跳转正确。
-
修改头像测试:检查头像上传功能是否正常。
-
修改昵称测试:输入新的昵称并保存,验证是否生效。
-
修改邮箱/手机号测试:更改邮箱或手机号,并检查更新后的信息。
-
修改个人简介测试:输入新简介并保存,检查是否成功。
-
修改密码测试:更改密码并使用新密码重新登录。
-
执行方式
-
在
RunTest.py
中调用PersonalHomepage
类执行测试。from common.Utils import Driver from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from pywinauto import Application from cases import Loginclass PersonalHomepage:url = ''driver = ''def __init__(self):# 初始化URL和driver,打开首页self.url = 'http://127.0.0.1:9580/index.html'self.driver = Driver.driverself.driver.get(self.url)# 等待页面加载完毕并确保头像元素可见WebDriverWait(self.driver,10).until(EC.presence_of_element_located((By.CSS_SELECTOR,'#index_nav_avatar')))# 点击头像,进入个人资料设置页面self.driver.find_element(By.CSS_SELECTOR,'#index_nav_avatar').click()# 等待个人设置按钮可点击,并点击进入WebDriverWait(self.driver,10).until(EC.presence_of_element_located((By.CSS_SELECTOR,'#index_user_settings')))self.driver.find_element(By.CSS_SELECTOR,'#index_user_settings').click()def test_switch_section(self):"""测试不同版块的切换功能"""try:# 等待“最新回复”板块加载,确保初始状态正确WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR,'#bit-forum-content > div.page-body > div > div > div:nth-child(2) > h3').text.strip() == "最新回复")except:pass # 忽略异常,继续执行# 断言当前版块为“最新回复”assert self.driver.find_element(By.CSS_SELECTOR,'#bit-forum-content > div.page-body > div > div > div:nth-child(2) > h3').text == "最新回复"# 切换到首页WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#nav_board_index > a > span.nav-link-title')))self.driver.find_element(By.CSS_SELECTOR, '#nav_board_index > a > span.nav-link-title').click()try:# 等待首页加载WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR,'#bit-forum-content > div.page-header.d-print-none > div > div > div > h2').text == "首页")except:pass # 忽略异常# 断言当前版块为“首页”assert self.driver.find_element(By.CSS_SELECTOR,'#bit-forum-content > div.page-header.d-print-none > div > div > div > h2').text == '首页'# 切换到“Java”版块WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#topBoardList > li:nth-child(2) > a > span.nav-link-title')))self.driver.find_element(By.CSS_SELECTOR, '#topBoardList > li:nth-child(2) > a > span.nav-link-title').click()try:# 等待“Java”版块加载WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == "Java")except:pass# 断言当前版块为“Java”assert self.driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == 'Java'# 切换到“C++”版块WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#topBoardList > li:nth-child(3) > a > span.nav-link-title')))self.driver.find_element(By.CSS_SELECTOR, '#topBoardList > li:nth-child(3) > a > span.nav-link-title').click()try:# 等待“C++”版块加载WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == "C++")except:pass# 断言当前版块为“C++”assert self.driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == 'C++'# 切换到“MySQL”版块WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#topBoardList > li:nth-child(5) > a > span.nav-link-title')))self.driver.find_element(By.CSS_SELECTOR, '#topBoardList > li:nth-child(5) > a > span.nav-link-title').click()try:# 等待“MySQL”版块加载WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == "MySQL")except:pass# 断言当前版块为“MySQL”assert self.driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == 'MySQL'def test_search_input(self):"""测试搜索框输入功能"""WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div.nav-item.d-none.d-md-flex.me-3 > div > form > div > input')))self.driver.find_element(By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div.nav-item.d-none.d-md-flex.me-3 > div > form > div > input').send_keys(123)# 断言输入的值是否正确assert self.driver.find_element(By.CSS_SELECTOR,"body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div.nav-item.d-none.d-md-flex.me-3 > div > form > div > input").get_attribute("value") == '123'def test_toggle_day_night_mode(self):"""测试日间/夜间模式切换"""WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > a.nav-link.px-0.hide-theme-dark > svg')))# 断言初始模式为日间模式assert self.driver.find_element(By.CSS_SELECTOR, 'body').get_attribute("class") == 'theme-light'# 切换到夜间模式self.driver.find_element(By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > a.nav-link.px-0.hide-theme-dark > svg').click()WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > a.nav-link.px-0.hide-theme-light > svg')))# 断言模式已切换为夜间模式assert self.driver.find_element(By.CSS_SELECTOR, 'body').get_attribute("class") == 'theme-dark'# 切换回日间模式self.driver.find_element(By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > a.nav-link.px-0.hide-theme-light > svg').click()def test_message_button(self):"""测试消息按钮是否可点击并弹出消息面板"""WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > div > a > svg')))self.driver.find_element(By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > div > a > svg').click()assert self.driver.find_element(By.CSS_SELECTOR, '#offcanvasEndLabel')def test_user_profile(self):"""测试用户个人信息是否正确显示"""self.driver.fullscreen_window()WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#index_nav_nickname')))assert self.driver.find_element(By.CSS_SELECTOR, '#index_nav_nickname').text == 'zhangsan'WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#index_nav_name_sub')))assert self.driver.find_element(By.CSS_SELECTOR, '#index_nav_name_sub').text == '普通用户'def test_change_avatar(self): # 头像修改测试# 等待并点击“更换头像”按钮WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR,'#bit-forum-content > div.page-body > div > div > div > div.col.d-flex.flex-column > div > div.row.align-items-center > div:nth-child(2) > a')))self.driver.find_element(By.CSS_SELECTOR,'#bit-forum-content > div.page-body > div > div > div > div.col.d-flex.flex-column > div > div.row.align-items-center > div:nth-child(2) > a').click()# 连接到“打开”窗口app = Application().connect(title_re='打开', timeout=1) # 连接到 "打开" 窗口dlg = app.window(title_re="打开") # 获取窗口assert dlg.existdlg.close()def test_nickname_field(self): # 昵称栏测试random_number = random.randint(100, 999)# 等待昵称输入框并进行操作WebDriverWait(self.driver,10).until(EC.presence_of_element_located((By.CSS_SELECTOR,'#setting_input_nickname')))nickname = self.driver.find_element(By.CSS_SELECTOR,'#setting_input_nickname')nickname.clear()nickname.send_keys(random_number)self.driver.find_element(By.CSS_SELECTOR,'#setting_submit_nickname').click()# 检查提示信息是否存在try:WebDriverWait(self.driver,5).until(EC.presence_of_element_located((By.CSS_SELECTOR,'body > div.jq-toast-wrap.bottom-right > div')))except:passassert self.driver.find_element(By.CSS_SELECTOR,'body > div.jq-toast-wrap.bottom-right > div').text# 恢复为默认的“zhangsan”昵称nickname.clear()nickname.send_keys('zhangsan')self.driver.find_element(By.CSS_SELECTOR,'#setting_submit_nickname').click()def test_email_field(self): # 邮箱栏测试random_number = random.randint(100000, 999999)# 等待邮箱输入框并进行操作WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#setting_input_email')))email = self.driver.find_element(By.CSS_SELECTOR, '#setting_input_email')email.clear()email.send_keys(f'{random_number}qq.com')self.driver.find_element(By.CSS_SELECTOR, '#setting_submit_email').click()# 检查提示信息是否存在try:WebDriverWait(self.driver, 5).until(EC.presence_of_element_located((By.CSS_SELECTOR, 'body > div.jq-toast-wrap.bottom-right > div')))except:passassert self.driver.find_element(By.CSS_SELECTOR, 'body > div.jq-toast-wrap.bottom-right > div')def test_phone_number_field(self): # 电话号码栏测试random_number = random.randint(10000000000, 99999999999)# 等待并操作电话号码输入框WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#setting_input_phoneNum')))phone = self.driver.find_element(By.CSS_SELECTOR, '#setting_input_phoneNum')phone.clear()phone.send_keys(random_number)self.driver.find_element(By.CSS_SELECTOR, '#setting_submit_phoneNum').click()# 检查提示信息是否存在try:WebDriverWait(self.driver, 5).until(EC.presence_of_element_located((By.CSS_SELECTOR, 'body > div.jq-toast-wrap.bottom-right > div')))except:passassert self.driver.find_element(By.CSS_SELECTOR, 'body > div.jq-toast-wrap.bottom-right > div')def test_bio_field(self): # 个人简介栏测试random_number = random.randint(10000000000, 99999999999)# 等待并操作个人简介输入框WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#settings_textarea_remark')))bio = self.driver.find_element(By.CSS_SELECTOR, '#settings_textarea_remark')# 滚动页面使元素可见self.driver.execute_script("arguments[0].scrollIntoView();", bio)time.sleep(0.5)bio.clear()bio.send_keys(random_number)self.driver.find_element(By.CSS_SELECTOR, '#settings_submit_remark').click()# 检查提示信息是否存在try:WebDriverWait(self.driver, 5).until(EC.presence_of_element_located((By.CSS_SELECTOR, 'body > div.jq-toast-wrap.bottom-right > div')))except:passassert self.driver.find_element(By.CSS_SELECTOR, 'body > div.jq-toast-wrap.bottom-right > div')def test_change_password(self): # 修改密码栏测试random_number = random.randint(100, 999)print(f'random_password:{random_number}')# 等待并操作旧密码、新密码、确认新密码输入框WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#settings_input_oldPassword')))oldpassword = self.driver.find_element(By.CSS_SELECTOR, '#settings_input_oldPassword')self.driver.execute_script("arguments[0].scrollIntoView();", oldpassword)oldpassword.clear()oldpassword.send_keys(1234)newpassword = self.driver.find_element(By.CSS_SELECTOR, '#settings_input_newPassword')self.driver.execute_script("arguments[0].scrollIntoView();", newpassword)newpassword.clear()newpassword.send_keys(random_number)cnewpassword = self.driver.find_element(By.CSS_SELECTOR, '#settings_input_passwordRepeat')self.driver.execute_script("arguments[0].scrollIntoView();", cnewpassword)cnewpassword.clear()cnewpassword.send_keys(random_number)element = self.driver.find_element(By.CSS_SELECTOR, '#settings_submit_password')self.driver.execute_script("arguments[0].scrollIntoView();", element)# 提交修改密码WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#settings_submit_password')))time.sleep(0.5)element.click()# 检查密码修改是否成功try:WebDriverWait(self.driver, 5).until(EC.presence_of_element_located((By.CSS_SELECTOR, 'body > div > div > div > div:nth-child(1) > div > div.card.card-md > div > h2')))except:passassert self.driver.find_element(By.CSS_SELECTOR, 'body > div > div > div > div:nth-child(1) > div > div.card.card-md > div > h2')# 使用新密码重新登录Login.Login()._login('zhangsan',f'{random_number}')WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#index_nav_avatar')))self.driver.find_element(By.CSS_SELECTOR, '#index_nav_avatar').click()WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#index_user_settings')))self.driver.find_element(By.CSS_SELECTOR, '#index_user_settings').click()WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#settings_input_oldPassword')))oldpassword = self.driver.find_element(By.CSS_SELECTOR, '#settings_input_oldPassword')self.driver.execute_script("arguments[0].scrollIntoView();", oldpassword)oldpassword.clear()oldpassword.send_keys(random_number)newpassword = self.driver.find_element(By.CSS_SELECTOR, '#settings_input_newPassword')self.driver.execute_script("arguments[0].scrollIntoView();", newpassword)newpassword.clear()# 恢复密码为初始值newpassword.send_keys(1234)cnewpassword = self.driver.find_element(By.CSS_SELECTOR, '#settings_input_passwordRepeat')self.driver.execute_script("arguments[0].scrollIntoView();", cnewpassword)cnewpassword.clear()cnewpassword.send_keys(1234)element = self.driver.find_element(By.CSS_SELECTOR, '#settings_submit_password')self.driver.execute_script("arguments[0].scrollIntoView();", element)WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#settings_submit_password')))time.sleep(0.5)element.click()
帖子编辑页自动化测试(Edit.py)
测试目标
-
确保帖子编辑页功能正常,包括输入标题、内容、板块选择及发布功能。
测试步骤
-
创建
Edit.py
,引入Utils.py
及相关依赖。 -
定义
Edit
类,管理帖子编辑页面的测试用例。 -
实现以下测试方法:
-
内容框测试:检查帖子内容输入框是否正确加载。
-
标题输入测试:输入标题并验证输入内容是否正确。
-
板块选择测试:选择不同板块,并检查选择结果是否正确。
-
发布测试:点击发布按钮并确保帖子成功发布并跳转到帖子列表页。
-
执行方式
-
在
RunTest.py
中调用Edit
类执行测试。import time from common.Utils import Driver from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import Selectclass Edit:driver = ''url = ''def __init__(self):# 初始化方法,打开指定的URLself.url = 'http://127.0.0.1:9580/index.html'self.driver = Driver.driverself.driver.get(self.url)WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#bit-forum-content > div.page-header.d-print-none > div > div > div.col-auto.ms-auto.d-print-none > div > a.btn.btn-primary.d-none.d-sm-inline-block.article_post')))# 点击进入文章发布页面self.driver.find_element(By.CSS_SELECTOR, '#bit-forum-content > div.page-header.d-print-none > div > div > div.col-auto.ms-auto.d-print-none > div > a.btn.btn-primary.d-none.d-sm-inline-block.article_post').click()def Content_Box(self):# 内容框测试,检查内容框是否存在WebDriverWait(self.driver,10).until(EC.presence_of_element_located((By.CSS_SELECTOR,'#edit-article > div.CodeMirror.cm-s-default.CodeMirror-wrap.CodeMirror-empty > div.CodeMirror-scroll > div.CodeMirror-sizer > div > div > div > div.CodeMirror-code > div > pre')))# 确认内容框是否已经加载self.driver.find_element(By.CSS_SELECTOR,'#edit-article > div.CodeMirror.cm-s-default.CodeMirror-wrap.CodeMirror-empty > div.CodeMirror-scroll > div.CodeMirror-sizer > div > div > div > div.CodeMirror-code > div > pre')def Title_Bar(self):# 标题栏测试,输入并验证标题内容WebDriverWait(self.driver,10).until(EC.presence_of_element_located((By.CSS_SELECTOR,'#article_post_title')))self.driver.find_element(By.CSS_SELECTOR,'#article_post_title').send_keys(1)assert self.driver.find_element(By.CSS_SELECTOR,'#article_post_title').get_attribute('value') == "1"def Plate_Selection(self):# 板块选择测试,检查板块选择器中的选项WebDriverWait(self.driver,10).until(EC.presence_of_element_located((By.CSS_SELECTOR,'#article_post_borad')))select = Select(self.driver.find_element(By.CSS_SELECTOR,'#article_post_borad'))options = [option.text for option in select.options]# 验证板块选项是否正确assert 'C++' in optionsassert '前端技术' in optionsassert 'MySQL' in optionsassert '面试宝典' in optionsassert '经验分享' in optionsassert '招聘信息' in optionsassert '福利待遇' in optionsassert '灌水区' in optionsselect.select_by_visible_text('C++')assert select.first_selected_option.text == 'C++'def Release(self):# 发布测试,点击发布按钮并验证发布反馈WebDriverWait(self.driver,10).until(EC.element_to_be_clickable((By.CSS_SELECTOR,'#article_post_submit')))self.driver.execute_script("arguments[0].scrollIntoView();",self.driver.find_element(By.CSS_SELECTOR,'#article_post_submit'))time.sleep(0.5)self.driver.find_element(By.CSS_SELECTOR,'#article_post_submit').click()try:WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, 'body > div.jq-toast-wrap.bottom-right > div')))except:pass# 确认发布后的反馈消息出现assert self.driver.find_element(By.CSS_SELECTOR,'body > div.jq-toast-wrap.bottom-right > div')def test_switch_section(self):"""测试不同版块的切换功能"""try:# 等待“最新回复”板块加载,确保初始状态正确WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR,'#bit-forum-content > div.page-body > div > div > div:nth-child(2) > h3').text.strip() == "最新回复")except:pass # 忽略异常,继续执行# 断言当前版块为“最新回复”assert self.driver.find_element(By.CSS_SELECTOR,'#bit-forum-content > div.page-body > div > div > div:nth-child(2) > h3').text == "最新回复"# 切换到首页WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#nav_board_index > a > span.nav-link-title')))self.driver.find_element(By.CSS_SELECTOR, '#nav_board_index > a > span.nav-link-title').click()try:# 等待首页加载WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR,'#bit-forum-content > div.page-header.d-print-none > div > div > div > h2').text == "首页")except:pass # 忽略异常# 断言当前版块为“首页”assert self.driver.find_element(By.CSS_SELECTOR,'#bit-forum-content > div.page-header.d-print-none > div > div > div > h2').text == '首页'# 切换到“Java”版块WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#topBoardList > li:nth-child(2) > a > span.nav-link-title')))self.driver.find_element(By.CSS_SELECTOR, '#topBoardList > li:nth-child(2) > a > span.nav-link-title').click()try:# 等待“Java”版块加载WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == "Java")except:pass# 断言当前版块为“Java”assert self.driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == 'Java'# 切换到“C++”版块WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#topBoardList > li:nth-child(3) > a > span.nav-link-title')))self.driver.find_element(By.CSS_SELECTOR, '#topBoardList > li:nth-child(3) > a > span.nav-link-title').click()try:# 等待“C++”版块加载WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == "C++")except:pass# 断言当前版块为“C++”assert self.driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == 'C++'# 切换到“MySQL”版块WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#topBoardList > li:nth-child(5) > a > span.nav-link-title')))self.driver.find_element(By.CSS_SELECTOR, '#topBoardList > li:nth-child(5) > a > span.nav-link-title').click()try:# 等待“MySQL”版块加载WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == "MySQL")except:pass# 断言当前版块为“MySQL”assert self.driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == 'MySQL'def test_search_input(self):"""测试搜索框输入功能"""WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div.nav-item.d-none.d-md-flex.me-3 > div > form > div > input')))self.driver.find_element(By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div.nav-item.d-none.d-md-flex.me-3 > div > form > div > input').send_keys(123)# 断言输入的值是否正确assert self.driver.find_element(By.CSS_SELECTOR,"body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div.nav-item.d-none.d-md-flex.me-3 > div > form > div > input").get_attribute("value") == '123'def test_toggle_day_night_mode(self):"""测试日间/夜间模式切换"""WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > a.nav-link.px-0.hide-theme-dark > svg')))# 断言初始模式为日间模式assert self.driver.find_element(By.CSS_SELECTOR, 'body').get_attribute("class") == 'theme-light'# 切换到夜间模式self.driver.find_element(By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > a.nav-link.px-0.hide-theme-dark > svg').click()WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > a.nav-link.px-0.hide-theme-light > svg')))# 断言模式已切换为夜间模式assert self.driver.find_element(By.CSS_SELECTOR, 'body').get_attribute("class") == 'theme-dark'# 切换回日间模式self.driver.find_element(By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > a.nav-link.px-0.hide-theme-light > svg').click()def test_message_button(self):"""测试消息按钮是否可点击并弹出消息面板"""WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > div > a > svg')))self.driver.find_element(By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > div > a > svg').click()assert self.driver.find_element(By.CSS_SELECTOR, '#offcanvasEndLabel')def test_user_profile(self):"""测试用户个人信息是否正确显示"""self.driver.fullscreen_window()WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#index_nav_nickname')))assert self.driver.find_element(By.CSS_SELECTOR, '#index_nav_nickname').text == 'zhangsan'WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#index_nav_name_sub')))assert self.driver.find_element(By.CSS_SELECTOR, '#index_nav_name_sub').text == '普通用户'
帖子详情页自动化测试(Detail.py)
测试目标
-
确保帖子详情页功能正常,包括查看、评论、点赞等功能。
测试步骤
-
创建
Detail.py
,引入Utils.py
及相关依赖。 -
定义
Detail
类,管理帖子详情页的测试用例。 -
实现以下测试方法:
-
查看博客测试:进入帖子详情页,确保内容正确显示。
-
评论测试:输入评论并提交,检查是否成功添加到页面。
-
点赞测试:点击点赞按钮,确认点赞数增加。
-
执行方式
-
在
RunTest.py
中调用Detail
类执行测试。import time from common.Utils import Driver from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as ECclass Detail:"""页面详情测试类,包含私信、帖子、评论、点赞等功能的测试"""driver = ''url = ''def __init__(self):"""初始化 WebDriver 并访问指定 URL"""self.driver = Driver.driverself.url = 'http://127.0.0.1:9580/index.html'self.driver.get(self.url)# 等待页面关键元素加载WebDriverWait(self.driver,10).until(EC.presence_of_element_located((By.CSS_SELECTOR,'#artical-items-body > div:nth-child(1) > div > div.col > div.text-truncate > a > strong')))# 点击文章进入详情页self.driver.find_element(By.CSS_SELECTOR,'#artical-items-body > div:nth-child(1) > div > div.col > div.text-truncate > a > strong').click()def Private_Message(self):"""测试私信发送功能"""WebDriverWait(self.driver,10).until(EC.presence_of_element_located((By.CSS_SELECTOR,'#btn_details_send_message')))self.driver.find_element(By.CSS_SELECTOR,'#btn_details_send_message').click()# 等待私信弹窗出现WebDriverWait(self.driver,10).until(EC.visibility_of_element_located((By.CSS_SELECTOR,'#index_message_modal > div > div > div.modal-header > h5')))assert self.driver.find_element(By.CSS_SELECTOR,'#index_message_modal > div > div > div.modal-header > h5').text == '发送站内信'# 发送内容并提交self.driver.find_element(By.CSS_SELECTOR,'#index_message_receive_content').send_keys('1')self.driver.find_element(By.CSS_SELECTOR,'#btn_index_send_message').click()# 等待发送成功的提示WebDriverWait(self.driver,10).until(EC.visibility_of_element_located((By.CSS_SELECTOR,'body > div.jq-toast-wrap.bottom-right > div')))# assert '成功' in self.driver.find_element(By.CSS_SELECTOR,'body > div.jq-toast-wrap.bottom-right > div').textdef Post(self):"""测试帖子内容是否正确加载"""WebDriverWait(self.driver,10).until(EC.presence_of_element_located((By.CSS_SELECTOR,'#details_article_content > p')))WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#details_article_content_title')))def Comment(self):"""测试评论功能"""WebDriverWait(self.driver,10).until(EC.visibility_of_element_located((By.CSS_SELECTOR,'#article_details_reply > div.CodeMirror.cm-s-default.CodeMirror-wrap.CodeMirror-empty > div.CodeMirror-scroll > div.CodeMirror-sizer > div > div > div > div.CodeMirror-code > div > pre')))# 滚动到评论框self.driver.execute_script("arguments[0].scrollIntoView();", self.driver.find_element(By.CSS_SELECTOR,'#article_details_reply > div.CodeMirror.cm-s-default.CodeMirror-wrap.CodeMirror-empty > div.CodeMirror-scroll > div.CodeMirror-sizer > div > div > div > div.CodeMirror-code > div > pre'))time.sleep(0.5) # 等待滚动完成self.driver.find_element(By.CSS_SELECTOR,'#details_btn_article_reply > span').click()# 确认评论成功提示WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, 'body > div.jq-toast-wrap.bottom-right > div')))assert '提示' in self.driver.find_element(By.CSS_SELECTOR, 'body > div.jq-toast-wrap.bottom-right > div').textdef Likes(self):"""测试点赞功能"""WebDriverWait(self.driver,10).until(EC.visibility_of_element_located((By.CSS_SELECTOR,'#details_article_likeCount')))old = int(self.driver.find_element(By.CSS_SELECTOR,'#details_article_likeCount').text)# 点击点赞按钮self.driver.find_element(By.CSS_SELECTOR,'#details_btn_like_count').click()# 等待点赞成功提示WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, 'body > div.jq-toast-wrap.bottom-right > div > h2')))# 验证点赞数是否增加assert old + 1 == int(self.driver.find_element(By.CSS_SELECTOR,'#details_article_likeCount').text)def test_switch_section(self):"""测试不同版块的切换功能"""try:# 等待“最新回复”板块加载,确保初始状态正确WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR, '#bit-forum-content > div.page-body > div > div > div:nth-child(2) > h3').text.strip() == "最新回复")except:pass# 忽略异常,继续执行# 断言当前版块为“最新回复”assert self.driver.find_element(By.CSS_SELECTOR,'#bit-forum-content > div.page-body > div > div > div:nth-child(2) > h3').text == "最新回复"# 切换到首页WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#nav_board_index > a > span.nav-link-title')))self.driver.find_element(By.CSS_SELECTOR, '#nav_board_index > a > span.nav-link-title').click()try:# 等待首页加载WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR,'#bit-forum-content > div.page-header.d-print-none > div > div > div > h2').text == "首页")except:pass# 忽略异常# 断言当前版块为“首页”assert self.driver.find_element(By.CSS_SELECTOR,'#bit-forum-content > div.page-header.d-print-none > div > div > div > h2').text == '首页'# 切换到“Java”版块WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#topBoardList > li:nth-child(2) > a > span.nav-link-title')))self.driver.find_element(By.CSS_SELECTOR, '#topBoardList > li:nth-child(2) > a > span.nav-link-title').click()try:# 等待“Java”版块加载WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == "Java")except:pass# 断言当前版块为“Java”assert self.driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == 'Java'# 切换到“C++”版块WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#topBoardList > li:nth-child(3) > a > span.nav-link-title')))self.driver.find_element(By.CSS_SELECTOR, '#topBoardList > li:nth-child(3) > a > span.nav-link-title').click()try:# 等待“C++”版块加载WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == "C++")except:pass# 断言当前版块为“C++”assert self.driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == 'C++'# 切换到“MySQL”版块WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#topBoardList > li:nth-child(5) > a > span.nav-link-title')))self.driver.find_element(By.CSS_SELECTOR, '#topBoardList > li:nth-child(5) > a > span.nav-link-title').click()try:# 等待“MySQL”版块加载WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == "MySQL")except:pass# 断言当前版块为“MySQL”assert self.driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == 'MySQL'def test_search_input(self):"""测试搜索框输入功能"""WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div.nav-item.d-none.d-md-flex.me-3 > div > form > div > input')))self.driver.find_element(By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div.nav-item.d-none.d-md-flex.me-3 > div > form > div > input').send_keys(123)# 断言输入的值是否正确assert self.driver.find_element(By.CSS_SELECTOR,"body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div.nav-item.d-none.d-md-flex.me-3 > div > form > div > input").get_attribute("value") == '123'def test_toggle_day_night_mode(self):"""测试日间/夜间模式切换"""WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > a.nav-link.px-0.hide-theme-dark > svg')))# 断言初始模式为日间模式assert self.driver.find_element(By.CSS_SELECTOR, 'body').get_attribute("class") == 'theme-light'# 切换到夜间模式self.driver.find_element(By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > a.nav-link.px-0.hide-theme-dark > svg').click()WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > a.nav-link.px-0.hide-theme-light > svg')))# 断言模式已切换为夜间模式assert self.driver.find_element(By.CSS_SELECTOR, 'body').get_attribute("class") == 'theme-dark'# 切换回日间模式self.driver.find_element(By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > a.nav-link.px-0.hide-theme-light > svg').click()def test_message_button(self):"""测试消息按钮是否可点击并弹出消息面板"""WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > div > a > svg')))self.driver.find_element(By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > div > a > svg').click()assert self.driver.find_element(By.CSS_SELECTOR, '#offcanvasEndLabel')def test_user_profile(self):"""测试用户个人信息是否正确显示"""self.driver.fullscreen_window()WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#index_nav_nickname')))assert self.driver.find_element(By.CSS_SELECTOR, '#index_nav_nickname').text == 'zhangsan'WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#index_nav_name_sub')))assert self.driver.find_element(By.CSS_SELECTOR, '#index_nav_name_sub').text == '普通用户'
首页自动化测试(HomePage.py)
测试目标
-
确保首页的基本交互功能正常,包括查看帖子列表、切换主题、搜索等。
测试步骤
-
创建
HomePage.py
,引入Utils.py
及相关依赖。 -
定义
HomePage
类,管理首页的测试用例。 -
实现以下测试方法:
-
博客列表测试:检查帖子列表是否正确加载。
-
搜索测试:输入关键词并验证搜索结果是否符合预期。
-
日夜模式切换测试:切换日间/夜间模式,并验证切换效果。
-
执行方式
-
在
RunTest.py
中调用HomePage
类执行测试。import time from common.Utils import Driver from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as ECclass HomePage:driver = ''url = ''def __init__(self):# 初始化URL和driverself.url = 'http://127.0.0.1:9580/index.html'self.driver = Driver.driverself.driver.get(self.url)def Button(self):# 等待"发新贴"按钮可点击,并点击它WebDriverWait(self.driver,10).until(EC.element_to_be_clickable((By.CSS_SELECTOR,'#bit-forum-content > div.page-header.d-print-none > div > div > div.col-auto.ms-auto.d-print-none > div > a.btn.btn-primary.d-none.d-sm-inline-block.article_post')))self.driver.find_element(By.CSS_SELECTOR,'#bit-forum-content > div.page-header.d-print-none > div > div > div.col-auto.ms-auto.d-print-none > div > a.btn.btn-primary.d-none.d-sm-inline-block.article_post').click()# 验证页面是否跳转到“发新贴”WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR,'#bit-forum-content > div.page-header.d-print-none > div > div > div > h2')))assert self.driver.find_element(By.CSS_SELECTOR,'#bit-forum-content > div.page-header.d-print-none > div > div > div > h2').text == '发新贴'def List(self):# 等待第一个帖子可点击,并点击它WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#artical-items-body > div:nth-child(1) > div > div.col > div.text-truncate > a > strong')))self.driver.find_element(By.CSS_SELECTOR,'#artical-items-body > div:nth-child(1) > div > div.col > div.text-truncate > a > strong').click()# 验证页面是否跳转到“最新回复”区域WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR,'#bit-forum-content > div.page-body > div > div > div:nth-child(2) > h3')))assert self.driver.find_element(By.CSS_SELECTOR,'#bit-forum-content > div.page-body > div > div > div:nth-child(2) > h3').text == '最新回复'def test_switch_section(self):"""测试不同版块的切换功能"""try:# 等待“最新回复”板块加载,确保初始状态正确WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR,'#bit-forum-content > div.page-body > div > div > div:nth-child(2) > h3').text.strip() == "最新回复")except:pass # 忽略异常,继续执行# 断言当前版块为“最新回复”assert self.driver.find_element(By.CSS_SELECTOR,'#bit-forum-content > div.page-body > div > div > div:nth-child(2) > h3').text == "最新回复"# 切换到首页WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#nav_board_index > a > span.nav-link-title')))self.driver.find_element(By.CSS_SELECTOR, '#nav_board_index > a > span.nav-link-title').click()try:# 等待首页加载WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR,'#bit-forum-content > div.page-header.d-print-none > div > div > div > h2').text == "首页")except:pass # 忽略异常# 断言当前版块为“首页”assert self.driver.find_element(By.CSS_SELECTOR,'#bit-forum-content > div.page-header.d-print-none > div > div > div > h2').text == '首页'# 切换到“Java”版块WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#topBoardList > li:nth-child(2) > a > span.nav-link-title')))self.driver.find_element(By.CSS_SELECTOR, '#topBoardList > li:nth-child(2) > a > span.nav-link-title').click()try:# 等待“Java”版块加载WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == "Java")except:pass# 断言当前版块为“Java”assert self.driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == 'Java'# 切换到“C++”版块WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#topBoardList > li:nth-child(3) > a > span.nav-link-title')))self.driver.find_element(By.CSS_SELECTOR, '#topBoardList > li:nth-child(3) > a > span.nav-link-title').click()try:# 等待“C++”版块加载WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == "C++")except:pass# 断言当前版块为“C++”assert self.driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == 'C++'# 切换到“MySQL”版块WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#topBoardList > li:nth-child(5) > a > span.nav-link-title')))self.driver.find_element(By.CSS_SELECTOR, '#topBoardList > li:nth-child(5) > a > span.nav-link-title').click()try:# 等待“MySQL”版块加载WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == "MySQL")except:pass# 断言当前版块为“MySQL”assert self.driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == 'MySQL'def test_search_input(self):"""测试搜索框输入功能"""WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div.nav-item.d-none.d-md-flex.me-3 > div > form > div > input')))self.driver.find_element(By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div.nav-item.d-none.d-md-flex.me-3 > div > form > div > input').send_keys(123)# 断言输入的值是否正确assert self.driver.find_element(By.CSS_SELECTOR,"body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div.nav-item.d-none.d-md-flex.me-3 > div > form > div > input").get_attribute("value") == '123'def test_toggle_day_night_mode(self):"""测试日间/夜间模式切换"""WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > a.nav-link.px-0.hide-theme-dark > svg')))# 断言初始模式为日间模式assert self.driver.find_element(By.CSS_SELECTOR, 'body').get_attribute("class") == 'theme-light'# 切换到夜间模式self.driver.find_element(By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > a.nav-link.px-0.hide-theme-dark > svg').click()WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > a.nav-link.px-0.hide-theme-light > svg')))# 断言模式已切换为夜间模式assert self.driver.find_element(By.CSS_SELECTOR, 'body').get_attribute("class") == 'theme-dark'# 切换回日间模式self.driver.find_element(By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > a.nav-link.px-0.hide-theme-light > svg').click()def test_message_button(self):"""测试消息按钮是否可点击并弹出消息面板"""WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > div > a > svg')))self.driver.find_element(By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > div > a > svg').click()assert self.driver.find_element(By.CSS_SELECTOR, '#offcanvasEndLabel')def test_user_profile(self):"""测试用户个人信息是否正确显示"""self.driver.fullscreen_window()WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#index_nav_nickname')))assert self.driver.find_element(By.CSS_SELECTOR, '#index_nav_nickname').text == 'zhangsan'WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#index_nav_name_sub')))assert self.driver.find_element(By.CSS_SELECTOR, '#index_nav_name_sub').text == '普通用户'
私信功能自动化测试(PrivateMessage.py)
测试目标
-
确保私信功能正常,包括查看和发送私信。
测试步骤
-
创建
PrivateMessage.py
,引入Utils.py
及相关依赖。 -
定义
PrivateMessage
类,管理私信的测试用例。 -
实现以下测试方法:
-
查看私信测试:进入私信列表并点击某条私信,检查内容是否正确显示。
-
发送私信测试:输入内容并发送,确保私信成功发送。
-
执行方式
-
在
RunTest.py
中调用PrivateMessage
类执行测试。import time from common.Utils import Driver from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as ECclass PrivateMessage:url = ''driver = ''def __init__(self):self.driver = Driver.driverself.url = 'http://127.0.0.1:9580/index.html'self.driver.get(self.url)WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > div > a > svg')))self.driver.find_element(By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > div > a > svg').click()assert self.driver.find_element(By.CSS_SELECTOR, '#offcanvasEndLabel')def reply(self):# 等待并点击私信列表中的第一条消息WebDriverWait(self.driver,10).until(EC.presence_of_element_located((By.CSS_SELECTOR,'#index_div_message_list > div:nth-child(1) > div > div.col.text-truncate > a')))self.driver.find_element(By.CSS_SELECTOR,'#index_div_message_list > div:nth-child(1) > div > div.col.text-truncate > a').click()# 等待 "取消回复" 按钮出现并点击WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, '#index_message_reply_cancel')))self.driver.find_element(By.CSS_SELECTOR,'#index_message_reply_cancel').click()# 再次点击同一条私信,重新进入回复界面WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#index_div_message_list > div:nth-child(1) > div > div.col.text-truncate > a')))self.driver.find_element(By.CSS_SELECTOR,'#index_div_message_list > div:nth-child(1) > div > div.col.text-truncate > a').click()# 等待 "回复" 按钮出现并点击WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, '#btn_index_message_reply')))self.driver.find_element(By.CSS_SELECTOR,'#btn_index_message_reply').click()# 等待回复输入框并输入消息WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#index_message_reply_receive_content')))self.driver.find_element(By.CSS_SELECTOR,'#index_message_reply_receive_content').send_keys(123)# 等待 "发送回复" 按钮出现并点击WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#btn_index_send_message_reply')))self.driver.find_element(By.CSS_SELECTOR, '#btn_index_send_message_reply').click()# 等待并检查是否有成功提示WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, 'body > div.jq-toast-wrap.bottom-right > div')))assert '成功' in self.driver.find_element(By.CSS_SELECTOR, 'body > div.jq-toast-wrap.bottom-right > div').text
我的帖子自动化测试(MyPost.py)
测试目标
-
确保“我的帖子”页面功能正常,包括查看、管理已发布的帖子。
测试步骤
-
创建
MyPost.py
,引入Utils.py
及相关依赖。 -
定义
MyPost
类,管理“我的帖子”页面的测试用例。 -
实现以下测试方法:
-
查看已发布帖子:进入“我的帖子”页面,检查列表是否正确显示。
-
编辑帖子测试:点击某个帖子进行编辑,检查是否能正常修改并保存。
-
删除帖子测试:删除某个帖子,并检查列表是否正确更新。
-
执行方式
-
在
RunTest.py
中调用MyPost
类执行测试。import time from common.Utils import Driver from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as ECclass MyPost:driver = ''url = ''def __init__(self):# 初始化URL和driver,打开用户首页self.url = 'http://127.0.0.1:9580/index.html'self.driver = Driver.driverself.driver.get(self.url)# 等待页面加载完毕,点击头像进入用户资料页面WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#index_nav_avatar')))self.driver.find_element(By.CSS_SELECTOR, '#index_nav_avatar').click()# 等待用户资料链接可点击,进入用户资料页面WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR,'#index_user_profile')))self.driver.find_element(By.CSS_SELECTOR,'#index_user_profile').click()def Name(self):# 等待用户昵称加载完成,并验证昵称是否为 'zhangsan'WebDriverWait(self.driver,10).until(EC.presence_of_element_located((By.CSS_SELECTOR,'#profile_nickname')))# 验证昵称是否正确assert self.driver.find_element(By.CSS_SELECTOR,'#profile_nickname').text == 'zhangsan'def Post(self):# 等待第一个帖子可点击WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#profile_article_body > li:nth-child(1) > div.card.timeline-event-card > div > div > div > div > div.text-truncate > a > strong')))self.driver.find_element(By.CSS_SELECTOR,'#profile_article_body > li:nth-child(1) > div.card.timeline-event-card > div > div > div > div > div.text-truncate > a > strong').click()try:# 等待文章编辑按钮出现,若出现则表示该帖子可以编辑WebDriverWait(self.driver,10).until(EC.presence_of_element_located((By.CSS_SELECTOR,'#details_artile_edit')))except:pass# 验证是否可以编辑帖子assert self.driver.find_element(By.CSS_SELECTOR,'#details_artile_edit')def test_switch_section(self):"""测试不同版块的切换功能"""try:# 等待“最新回复”板块加载,确保初始状态正确WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR,'#bit-forum-content > div.page-body > div > div > div:nth-child(2) > h3').text.strip() == "最新回复")except:pass # 忽略异常,继续执行# 断言当前版块为“最新回复”assert self.driver.find_element(By.CSS_SELECTOR,'#bit-forum-content > div.page-body > div > div > div:nth-child(2) > h3').text == "最新回复"# 切换到首页WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#nav_board_index > a > span.nav-link-title')))self.driver.find_element(By.CSS_SELECTOR, '#nav_board_index > a > span.nav-link-title').click()try:# 等待首页加载WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR,'#bit-forum-content > div.page-header.d-print-none > div > div > div > h2').text == "首页")except:pass # 忽略异常# 断言当前版块为“首页”assert self.driver.find_element(By.CSS_SELECTOR,'#bit-forum-content > div.page-header.d-print-none > div > div > div > h2').text == '首页'# 切换到“Java”版块WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#topBoardList > li:nth-child(2) > a > span.nav-link-title')))self.driver.find_element(By.CSS_SELECTOR, '#topBoardList > li:nth-child(2) > a > span.nav-link-title').click()try:# 等待“Java”版块加载WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == "Java")except:pass# 断言当前版块为“Java”assert self.driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == 'Java'# 切换到“C++”版块WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#topBoardList > li:nth-child(3) > a > span.nav-link-title')))self.driver.find_element(By.CSS_SELECTOR, '#topBoardList > li:nth-child(3) > a > span.nav-link-title').click()try:# 等待“C++”版块加载WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == "C++")except:pass# 断言当前版块为“C++”assert self.driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == 'C++'# 切换到“MySQL”版块WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#topBoardList > li:nth-child(5) > a > span.nav-link-title')))self.driver.find_element(By.CSS_SELECTOR, '#topBoardList > li:nth-child(5) > a > span.nav-link-title').click()try:# 等待“MySQL”版块加载WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == "MySQL")except:pass# 断言当前版块为“MySQL”assert self.driver.find_element(By.CSS_SELECTOR, '#article_list_board_title').text == 'MySQL'def test_search_input(self):"""测试搜索框输入功能"""WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div.nav-item.d-none.d-md-flex.me-3 > div > form > div > input')))self.driver.find_element(By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div.nav-item.d-none.d-md-flex.me-3 > div > form > div > input').send_keys(123)# 断言输入的值是否正确assert self.driver.find_element(By.CSS_SELECTOR,"body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div.nav-item.d-none.d-md-flex.me-3 > div > form > div > input").get_attribute("value") == '123'def test_toggle_day_night_mode(self):"""测试日间/夜间模式切换"""WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > a.nav-link.px-0.hide-theme-dark > svg')))# 断言初始模式为日间模式assert self.driver.find_element(By.CSS_SELECTOR, 'body').get_attribute("class") == 'theme-light'# 切换到夜间模式self.driver.find_element(By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > a.nav-link.px-0.hide-theme-dark > svg').click()WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > a.nav-link.px-0.hide-theme-light > svg')))# 断言模式已切换为夜间模式assert self.driver.find_element(By.CSS_SELECTOR, 'body').get_attribute("class") == 'theme-dark'# 切换回日间模式self.driver.find_element(By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > a.nav-link.px-0.hide-theme-light > svg').click()def test_message_button(self):"""测试消息按钮是否可点击并弹出消息面板"""WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > div > a > svg')))self.driver.find_element(By.CSS_SELECTOR,'body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div:nth-child(2) > div > a > svg').click()assert self.driver.find_element(By.CSS_SELECTOR, '#offcanvasEndLabel')def test_user_profile(self):"""测试用户个人信息是否正确显示"""self.driver.fullscreen_window()WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#index_nav_nickname')))assert self.driver.find_element(By.CSS_SELECTOR, '#index_nav_nickname').text == 'zhangsan'WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#index_nav_name_sub')))assert self.driver.find_element(By.CSS_SELECTOR, '#index_nav_name_sub').text == '普通用户'
运行所有测试(RunTest.py)
测试目标
-
依次执行所有测试,并确保最终关闭 WebDriver。
测试步骤
-
创建
RunTest.py
,引入Utils.py
及所有测试文件。 -
依次调用各个测试类的测试方法。
-
统一管理 WebDriver 的初始化和退出。
执行方式
-
直接运行
RunTest.py
,所有测试会自动执行。
import time
from common.Utils import Driver
from cases import Login,PersonalHomepage,Edit,Detail,PrivateMessage,HomePage,MyPost,Register# 运行登录相关的测试
def run_Login_tests():"""执行所有登录相关的测试"""login = Login.Login() # 只实例化一次,避免重复创建对象login.login_suc_test1()login.login_suc_test2()login.test_login_empty_username_empty_password()login.test_login_empty_username_valid_password()login.test_login_empty_username_invalid_password()login.test_login_invalid_username_empty_password()login.test_login_valid_username_empty_password()login.test_login_valid_username_invalid_password()login.test_login_invalid_username_valid_password()login.test_login_invalid_username_invalid_password()# 运行个人主页相关的测试
def run_PersonalHomepage_tests():"""执行所有个人主页相关的测试"""personal_home = PersonalHomepage.PersonalHomepage()personal_home.test_switch_section()personal_home.test_search_input()personal_home.test_toggle_day_night_mode()personal_home.test_message_button()personal_home.test_user_profile()personal_home.test_change_avatar()personal_home.test_nickname_field()personal_home.test_email_field()personal_home.test_phone_number_field()personal_home.test_bio_field()personal_home.test_change_password()# 运行帖子编辑相关的测试
def run_Edit_tests():"""执行所有帖子编辑相关的测试"""edit = Edit.Edit()edit.Content_Box()edit.Title_Bar()edit.Plate_Selection()edit.Release()edit.test_switch_section()edit.test_search_input()edit.test_toggle_day_night_mode()edit.test_message_button()edit.test_user_profile()# 运行帖子详情相关的测试
def run_Detail_tests():"""执行所有帖子详情页面相关的测试"""detail = Detail.Detail()detail.Private_Message()detail.Post()detail.Comment()detail.Likes()detail.test_switch_section()detail.test_search_input()detail.test_toggle_day_night_mode()detail.test_message_button()detail.test_user_profile()# 运行私信功能的测试
def run_PrivateMessage_tests():"""执行私信功能的测试"""private_msg = PrivateMessage.PrivateMessage()private_msg.reply()# 运行首页相关的测试
def run_HomePage_tests():"""执行所有首页相关的测试"""home = HomePage.HomePage()home.Button()home.List()home.test_switch_section()home.test_search_input()home.test_toggle_day_night_mode()home.test_message_button()home.test_user_profile()# 运行“我的帖子”相关的测试
def run_MyPost_test():"""执行所有‘我的帖子’相关的测试"""my_post = MyPost.MyPost()my_post.Name()my_post.Post()my_post.test_switch_section()my_post.test_search_input()my_post.test_toggle_day_night_mode()my_post.test_message_button()my_post.test_user_profile()# 运行注册功能的测试
def run_Register_test():"""执行所有注册功能的测试"""register = Register.Register()register.test_valid_inputs_agree_terms()register.test_valid_username_empty_others_disagree_terms()register.test_empty_username_valid_nickname_mixed_passwords_disagree_terms()register.test_empty_username_nickname_valid_password_agree_terms()register.test_valid_inputs_missing_confirm_password_disagree_terms()register.test_valid_username_empty_nickname_password_confirmed_agree_terms()register.test_invalid_inputs_disagree_terms()# 运行所有测试
def run_all_tests():"""依次执行所有的测试,并在结束后关闭 WebDriver"""try:run_Login_tests()run_PersonalHomepage_tests()run_Edit_tests()run_Detail_tests()run_PrivateMessage_tests()run_HomePage_tests()run_MyPost_test()run_Register_test()except Exception as e:print(f"错误发生: {e}") # 捕获异常,避免测试中断finally:Driver.driver.quit() # 测试完成后关闭 WebDriver# 主函数
if __name__ == '__main__':run_all_tests()
可优化部分
- 菜单反复调用测试,可以专门写一个对菜单功能测试的函数
- 注释没有统一格式
- 好多地方截图没补上去
前面几个像登录测试注册那种选择多的是用 allpairs搞定的
3.各函数作用总览
Utils.py
-
__init__(self)
: 初始化 WebDriver。 -
getScreenShot(self)
: 截取当前页面截图并保存。
Login.py
-
__init__(self)
: 初始化 WebDriver 并打开登录页面。 -
_login(self, username, password)
: 输入用户名和密码,执行登录操作。 -
_verify_login_success(self)
: 验证用户是否成功登录。 -
login_suc_test1(self)
: 测试正确的用户名和密码能否成功登录。 -
login_suc_test2(self)
: 测试另一个正确的用户名和密码登录是否成功。 -
test_login_empty_username_empty_password(self)
: 测试用户名和密码都为空的情况。 -
test_login_valid_username_empty_password(self)
: 测试用户名正确但密码为空的情况。 -
test_login_invalid_username_valid_password(self)
: 测试用户名错误但密码正确的情况。
Register.py
-
__init__(self)
: 初始化 WebDriver 并打开注册页面。 -
test_valid_inputs_agree_terms(self)
: 测试所有输入正确且同意条款的情况。 -
test_valid_username_empty_others_disagree_terms(self)
: 测试仅填写用户名,其他字段为空且不同意条款的情况。 -
test_empty_username_valid_nickname_mixed_passwords_disagree_terms(self)
: 测试用户名为空、昵称有效但密码不匹配的情况。 -
test_empty_username_nickname_valid_password_agree_terms(self)
: 测试用户名和昵称为空,密码正确且同意条款的情况。
Edit.py
-
__init__(self)
: 初始化 WebDriver 并进入编辑页面。 -
Content_Box(self)
: 检查博客内容输入框是否正确加载。 -
Title_Bar(self)
: 输入标题并验证输入是否正确。 -
Plate_Selection(self)
: 选择不同的板块,并检查选择结果是否正确。 -
Release(self)
: 点击发布按钮,确保博客成功发布。 -
test_switch_section(self)
: 测试博客发布后页面是否能正确跳转到博客列表。
Detail.py
-
__init__(self)
: 初始化 WebDriver 并打开博客详情页。 -
Private_Message(self)
: 测试私信功能,确保发送私信成功。 -
Post(self)
: 测试博客内容是否正确显示。 -
Comment(self)
: 测试用户能否成功发表评论。 -
Likes(self)
: 测试点赞按钮是否正常工作。
PersonalHomepage.py
-
__init__(self)
: 初始化 WebDriver 并打开个人主页。 -
test_change_avatar(self)
: 测试头像修改功能。 -
test_nickname_field(self)
: 测试修改昵称并检查是否保存成功。 -
test_email_field(self)
: 测试修改邮箱并验证更新后的信息。 -
test_phone_number_field(self)
: 测试修改手机号功能。 -
test_bio_field(self)
: 测试个人简介的编辑与保存功能。 -
test_change_password(self)
: 测试修改密码,并使用新密码重新登录。
PrivateMessage.py
-
__init__(self)
: 初始化 WebDriver 并进入私信页面。 -
reply(self)
: 测试私信回复功能,确保发送成功。
HomePage.py
-
__init__(self)
: 初始化 WebDriver 并打开首页。 -
Button(self)
: 测试首页“发新贴”按钮是否能正常跳转到编辑页面。 -
List(self)
: 测试博客列表是否正确加载,并可点击查看详情。 -
test_search_input(self)
: 测试搜索框输入内容,并检查搜索结果。 -
test_toggle_day_night_mode(self)
: 测试日间/夜间模式的切换功能。
MyPost.py
-
__init__(self)
: 初始化 WebDriver 并进入“我的帖子”页面。 -
Name(self)
: 检查用户名是否正确显示。 -
Post(self)
: 测试点击某个帖子,确保页面跳转正常。
Test.py
-
run_all_tests()
: 运行所有测试用例,确保所有功能正常执行。
4.测试环境与执行方式
运行环境
-
Python 版本:3.13
-
依赖库:
selenium
-
浏览器:Microsoft Edge 版本 134.0.3124.68 (正式版本) (64 位)
-
WebDriver:
msedgedriver
需正确配置
运行方式
-
安装
selenium
依赖:pip install selenium
-
确保
msedgedriver
已正确安装。 -
运行
RunCases.py
以执行完整的测试流程:python RunCases.py
结果验证
-
所有测试案例执行完成后,测试日志将会记录各个测试步骤的执行结果。
-
关键页面截图将在
images/
目录中保存,以供参考。 -
若有测试失败,请参考日志进行问题排查,并根据错误信息调整代码或系统设置。
5.自动化框架特点与亮点
特点
该自动化测试框架结合了 Selenium WebDriver 与 自定义测试模块,能够高效地验证论坛的各项功能。测试用例覆盖了从 用户注册、登录、发布帖子、浏览帖子、私信交互、个人信息管理 到 页面跳转 等多个关键场景。
所有测试用例都封装为独立的函数,目标明确,执行步骤清晰,便于维护和扩展。自动化测试可以反复执行,提高测试覆盖率的同时,也减少了人工干预,提高测试效率。
此外,该框架还利用 Selenium WebDriver 的等待机制,确保页面元素完全加载后再执行操作,减少因页面加载缓慢导致的测试失败。同时,截图功能 使得测试过程可追踪,异常情况可视化,便于快速定位问题。
亮点
1. 统一的 WebDriver 管理
-
采用 Driver 类 统一管理 WebDriver 实例,避免每个测试用例重复创建 WebDriver,减少资源浪费,提高执行效率。
-
通过 单例模式 复用 WebDriver,在多个测试用例间共享浏览器会话,减少重复初始化的开销。
2. 功能清晰的测试用例
-
每个测试用例都封装成独立的函数,清晰定义测试目标和验证条件,增强了代码的可读性和可维护性。
-
测试覆盖了帖子网站的核心功能,包括:
-
用户注册与登录:模拟不同用户的登录情况,验证账号验证逻辑。
-
帖子管理:测试帖子的发布、编辑、删除等功能,确保用户可以正常管理文章。
-
交互功能:测试评论、私信、点赞等用户互动功能,确保社交体验顺畅。
-
3. 高效的等待机制
-
结合 显式等待 (WebDriverWait) 和 隐式等待,有效解决页面加载速度和测试执行速度不一致的问题。
-
避免因为页面元素未完全渲染而导致的
NoSuchElementException
或ElementNotInteractableException
,提高测试稳定性和可靠性。
4. 自动截图功能
-
每个测试用例执行时,自动截图关键操作,便于在测试失败时进行问题追踪和回溯。
-
结合 日志记录功能,在测试失败时保存错误信息,帮助开发人员快速定位和修复问题。
5. 自动化的重复执行
-
该框架可以轻松地多次执行同一组测试,适用于回归测试和稳定性测试,确保系统在不同时间段或高并发情况下依然表现正常。
-
结合 定时任务 (cron jobs) 或 CI/CD 流水线,可实现每日自动化回归测试,保证系统功能始终可用。
6. 页面元素检查与交互验证
-
通过 WebDriver 的
presence_of_element_located()
和visibility_of_element_located()
方法,确保所有关键元素在交互前正确加载。 -
检测页面上的按钮、表单、文本框等控件是否可点击、可输入、可提交,防止界面交互异常。
6.性能测试
使用 Apache JMeter 对 论坛系统 进行性能测试,模拟不同用户操作下的系统响应情况,确保系统能够在高并发访问下稳定运行。
测试目标
-
评估 用户登录、浏览帖子、查看详情、发表帖子 等关键功能的响应时间和吞吐量
-
通过 并发请求模拟大量用户访问,检查系统的稳定性
-
记录并分析 响应时间、线程活动情况、事务处理速度,优化系统性能
测试步骤
-
HTTP 请求默认值设置:定义论坛系统的基本 URL,简化后续请求配置
-
HTTP 头信息管理器:设置请求头,模拟真实浏览器访问
-
自定义变量:定义通用变量,便于动态参数传递
-
账号密码 CSV 数据管理:使用 CSV 文件导入用户信息,模拟多个用户登录
-
HTTP Cookie 管理器:存储会话信息,确保用户身份在请求间保持一致
-
执行测试事务:
-
用户登录:模拟用户输入账号密码并登录
-
用户信息:获取用户的个人资料
-
列表页:访问帖子列表,测试加载速度
-
详情页:查看特定帖子内容,测试响应时间
-
添加帖子:模拟用户发布新帖,验证提交效率
-
-
结果分析
-
查看结果树:检查每个请求的详细响应数据
-
聚合报告:统计请求数量、平均响应时间、吞吐量等指标
-
JMeter 监控插件
-
Active Threads Over Time:观察系统在不同时间点的并发用户数
-
Response Times Over Time:分析不同时间点的服务器响应时间
-
Transactions per Second:统计系统每秒钟处理的事务数
-
-
列表那异常爆表了啊
应该是那一页数据太多的问题
性能测试还在学,这就测的大概,看个乐
8.完整测试代码连接
GitHub - bbppooii/Automated-testing-of-forum-system
bbppooi/论坛系统自动化测试