[软件测试] 考试问卷通
一.测试目的及任务概括
对考试问卷通系统开展整体功能测试验证,全面核查系统所有模块的功能完整性;针对用户登录、用户注册、首页、我的项目、我的练习、题库中心、模板广场、系统管理等核心功能模块进行专项测试,验证各模块内容均满足业务需求与设计规范,确保系统核心功能合规可用。
二.测试环境
| 类别 | 配置 |
|---|---|
| 手动测试浏览器 | Google Chrome版本 151.0.7922.72 |
| 自动化测试工具 | PyCharm 2023.3.2、pytest 9.1.1、allure-pytest 2.16.0、selenium 4.0.0 |
| 操作系统 | Windows 11 |
| 自动化测试浏览器 | Google Chrome版本 151.0.7922.72 |
三、测试用例设计
3.1 登录界面测试用例设计
3.2 注册页面测试用例设计
3.3 主页面测试用例设计
四、手动测试系统
由于测试场景非常多,这里只展示部分功能
4.1、注册页面测试
测试场景:输入姓名,登录账号,密码,和确认密码,最后点击注册按钮
预期结果:注册成功
4.2、登录页面测试
测试场景:输入用户名和密码,点击登录按钮
预期结果:登录成功
4.3、首页测试
① 测试场景:点击“创建问卷”按钮
预期结果:成功跳转到问卷编辑页面
4.4、页面设置测试
① 测试场景:点击右上角齿轮按钮
预期结果:正常弹出功能
② 测试场景:点击“整体风格设置”按钮,同时选择暗色
预期结果:正常弹出选项框,并且页面主题色变为暗色
③ 测试场景:点击“用户设置”按钮
预期结果:成功跳转到“个人设置”页面
④ 测试场景:点击“退出登录”按钮
预期结果:成功跳转到登录页面
4.5、我的项目页面
① 测试场景:点击搜索框,输入已创建的项目名称
预期结果:显示搜索的项目
② 测试场景:点击右上角“新建”按钮
预期结果:正常弹出需要新建的功能选项
③ 测试场景:点击“问卷调查”按钮
预期结果:成功跳转到编辑问卷页面
④ 测试场景:点击“创建考试”按钮
预期结果:成功跳转到考试编辑页面
⑤ 测试场景:点击“回收站”按钮
预期结果:成功弹出回收站弹窗
⑥ 测试场景:选择一个项目,点击彻底删除
预期结果:成功弹出提示框
⑦ 测试场景:点击“删除”按钮
预期结果:弹出是否删除框
⑧ 测试场景:点击“小学数学”的项目
预期结果:成功跳转到项目设置页面
⑨ 测试场景:开启问卷后,点击“打开”按钮并作答
预期结果:跳转到正式问卷,可以作答并提交,提交后项目状态由未发布变为收集中
4.6、我的练习页面
① 测试场景:点击状态选择框,选择“正在进行”,再点击“查询”按钮
预期结果:正确筛选出符合条件的练习
② 测试场景:点击“重置”按钮
预期结果:状态选择框清空,下方显示全部我的练习
4.7、我的题库页面
① 测试场景:输入题库名称,选择类型,点击“查询”按钮
预期结果:查询出符合条件的题库
② 测试场景:点击“重置”按钮
预期结果:名称框清空,下方显示全部题库列表
③ 测试场景:点击“新建”按钮
预期结果:右侧弹出新增题库编辑页面
④ 测试场景:编辑题库名称为:语文1 、题库类型为考试,点击右下方“确定”按钮
预期结果:主页面成功显示名为语文1,类型为考试的题库
⑤ 测试场景:编辑题库名称为空
预期结果:提示题库名称不能为空
⑥ 测试场景:题库类型未选择
预期结果:提示请选择题库类型
五、兼容性测试
① 测试场景:在Chrome浏览器进入问卷考试系统
预期结果:无异常且一切布局显示功能等与其一致
② 测试场景:在Edge浏览器进入问卷考试系统
预期结果:无异常且一切布局显示功能等与其一致
六、UI自动化测试
6.1 系统整体架构设计
base包中存放被所有页继承的base_page基础页(存放通用的点击、文本输入等方法)和浏览器驱动信息
config包中存放配置有关的内容,包括基础配置数据和用于读取数据配置的配置类
flows包中存放模拟流程相关的测试用例,比如登录、注册、问卷、考试等一系列具体流程的总体测试
pages中包含登录页、注册页、项目首页、我的项目页等具体页面信息,所有页继承于base_page基础页,同时各个页中实现各自页面的基本功能
reports包中存放日志和截图相关的包,所有的日志和屏幕截图均放在此包下
utils包中存放一些通用的工具类,比如日志工具、配置读取工具、显示等待工具等
conftest.py是pytest 全局配置文件。通过 Fixture 机制统一管理测试用例的前置准备(如浏览器启动)和后置清理(如浏览器关闭),实现测试环境的初始化和资源释放。
6.2、导入需要下载的包
所有需要安装的包都保存在requestments.txt文件中,将其放在当前项目目录下,使用终端命令
pip install -r requestments.txt以下是requestments.txt文件的具体内容:
使用pytest框架+selenium浏览器核心操作库,搭配webdriver-manager自动搭配管理浏览器,同时使用allure生成可视化报告,以这样的一套ui自动化测试框架,实现核心业务的自动化回归测试。
6.3、公共工具包utils
工具包内主要包括configReader_util(配置读取)、logger_util(日志)、screeshot_util(屏幕截图)、wait_util(显示等待)
6.3.1、configReader_util —— 配置读取工具
作用:从config.json文件中读取数据
import json import os class ConfigReader: # 存储配置数据 _config =None # 获取配置数据 @classmethod def get_config(cls): if cls._config is None: # 找到config.json路径 current_dir = os.path.dirname(__file__) config_path = os.path.join(current_dir, "..","config","config.json") with open(config_path,"r",encoding="utf-8") as f: cls._config = json.load(f) return cls._config6.3.2、logger_util —— 日志工具
作用:给关键操作进行日志记录
基本步骤:
输入参数:日志名,日志等级,是否记录到文件
创建日志对象,命名并添加日志等级
创建日志格式器
创建日志处理器,指定存放路径,并将日志格式器设置到日志处理器中
将配合好的日志处理器添加到日志对象中
import logging import sys import time class Logger: # 缓存日志对象 loggers={} @classmethod def get_logger(cls,name=None,log_level=None,log_to_file=True): if name is None: name="ExamFlow" if log_level is None: log_level=logging.INFO if name in cls.loggers: return cls.loggers[name] # 创建日志对象 logger=logging.getLogger(name) logger.setLevel(log_level) # 设置日志格式器 formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S' ) # 创建输出控制台处理器 console_handler = logging.StreamHandler(sys.stdout) console_handler.setFormatter(formatter) logger.addHandler(console_handler) # 判断是否要将文件输出到日志 if log_to_file: log_dir="reports/logs" timestamp=time.strftime("%Y%m%d-%H%M%S") log_file= log_dir + "/" +timestamp + ".log" # 创建文件处理器 file_handler = logging.FileHandler(log_file,encoding="utf-8") file_handler.setFormatter(formatter) logger.addHandler(file_handler) cls.loggers[name]=logger return cls.loggers[name]6.3.3、screenshot_util —— 屏幕截图工具
作用:记录操作执行时,页面的相应效果
基本步骤:
- 优先判断浏览器驱动是否开启
- 创建屏幕截图存放的文件夹路径
- 调用driver.save_screenshot("具体地址"),进行截图同时输出日志信息
import time from utils.logger_util import Logger logger =Logger.get_logger(__name__) class ScreenShotUtil: @classmethod def take_screenshot(cls,driver): if driver is None: logger.warning("driver为空,无法截图") return None try: screenshot_dir = "reports/screenshots" timestamp = time.strftime("%Y%m%d-%H%M%S") screenshot_path = screenshot_dir + "/" + timestamp + ".png" # 进行截图 driver.save_screenshot(screenshot_path) logger.info(f"截图已保存: {screenshot_path}") return screenshot_path except Exception as e: logger.error(f"截图失败: {e}") return None6.3.4、wait_util —— 显示等待工具
作用:将等待于元素加载、等待元素可见、等待元素可点击等显示等待基本操作进行封装,以便后续直接调用,分工明确
基本步骤:
构造函数初始化浏览器驱动、超时时间
每个基本方法传入参数:定位器、超时时间和超时时需要输出的错误信息
每个基本方法内部调用符合需求的显示等待方法,并打印日志信息;对于出现异常的情况同样生效
注:以下代码仅示范部分显示等待
from selenium.common import TimeoutException from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.wait import WebDriverWait from utils.logger_util import Logger logger = Logger().get_logger(__name__) class WaitUtil: def __init__(self,driver,timeout): self.driver=driver self.timeout=timeout self.wait=WebDriverWait(self.driver,self.timeout) # 等待元素加载 def wait_locate_element(self,locator,timeout=None,msg=None): timeout=timeout or self.timeout try: return WebDriverWait(self.driver,timeout).until( EC.presence_of_element_located(locator), message=msg ) except TimeoutException as e: logger.error(f"等待元素超时:{locator},错误:{e}") raise # 等待元素可见 def wait_for_visible(self,locator,timeout=None,msg=None): timeout=timeout or self.timeout try: return WebDriverWait(self.driver,timeout).until( EC.visibility_of_element_located(locator), message=msg ) except TimeoutException as e: logger.error(f"等待元素可见超时:{locator},错误:{e}") raise # 等待元素可点击 def wait_for_clickable(self,locator,timeout=None,msg=None): timeout=timeout or self.timeout try: return WebDriverWait(self.driver,timeout).until( EC.element_to_be_clickable(locator), message=msg ) except TimeoutException as e: logger.error(f"等待元素可点击超时:{locator},错误:{e}") raise6.4、config包
① config包,存放config.py文件和config.json数据
② config.json中存放基础url、超时等待时间、是否开启无头模式、日志等级和默认用户名和密码等信息
{ "base_url": "http://49.235.61.184:8080", "timeout": 10, "headless": false, "log_level": "INFO", "default_user": { "username": "111111", "password": "111111" } }③ config.py中通过configReader_util工具读取config.json中的数据信息
6.5、基础包base
6.5.1、base_page —— 封装页的基本操作
主要对每个页的常用操作进行封装,比如点击元素、给元素输入文本、获取文本值、获取当前页面url等
from selenium.webdriver.support.wait import WebDriverWait from config.config import TIMEOUT from utils.logger_util import Logger from utils.screenshot_util import ScreenShotUtil from utils.wait_util import WaitUtil logger = Logger().get_logger() class BasePage: # 点击 def click(self,locator,timeout=None): element = self.wait_util.wait_for_clickable(locator,timeout) element.click() self.logger.info(f"点击元素 {locator}") return self # 输入文本 def input_text(self,locator,text,timeout=None,clear=True): element = self.wait_util.wait_for_visible(locator,timeout) if clear: element.clear() element.send_keys(text) self.logger.info(f"输入内容:{text}") return self # 获取文本 def get_text(self,locator,timeout=None): element = self.wait_util.wait_for_visible(locator,timeout) self.logger.info(f"获取文本信息:{element.text}") return element.text # 获取当前页面url def get_url(self): return self.driver.current_url6.5.2、driver_manager —— 浏览器驱动管理
主要用于浏览器驱动driver操作的封装
from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.chrome.service import Service from webdrivermanager_cn.chrome import ChromeDriverManager from utils.logger_util import Logger logger = Logger.get_logger(__name__) class DriverManager: _driver = None # 创建驱动 @classmethod def create_driver(cls,headless=False): # 驱动管理选项 options = Options() if headless: options.add_argument('--headless') # 添加常用优化项 options.add_argument("--disable-gpu") options.add_argument("--no-sandbox") options.add_argument("--disable-dev-shm-usage") options.add_argument("--window-size=1920,1080") # 禁用日志输出(减少控制台干扰) options.add_experimental_option("excludeSwitches", ["enable-logging"]) # 管理驱动版本 service =Service(ChromeDriverManager().install()) # 创建驱动 driver = webdriver.Chrome(service=service,options=options) # 窗口最大化,方便截图 driver.maximize_window() return driver6.6、具体页包pages
仅展示部分页的具体代码
6.6.1、login_page —— 登录页
从网页上或获取CSS SELECTROR信息,将定位信息封装为元素作为定位器进行创建,最后selenium通过定位器去页面中寻找对应的元素
from selenium.webdriver.common.by import By from base.base_page import BasePage class LoginPage(BasePage): # 定位器 USERNAME_INPUT=(By.CSS_SELECTOR,"#username") PASSWORD_INPUT=(By.CSS_SELECTOR,"#password") LOGIN_BTN=(By.CSS_SELECTOR,"#root > div > div.content___2zk1- > div.main___x4OjT > div > form > button") # 输入用户名 def input_username(self,username): self.input_text(self.USERNAME_INPUT,username) return self # 输入密码 def input_password(self,password): self.input_text(self.PASSWORD_INPUT,password) return self # 点击登录按钮(不跳转) def click_login(self): self.click(self.LOGIN_BTN) return self # 点击登录按钮并等待跳转到首页 def click_login_and_wait(self): self.click(self.LOGIN_BTN) self.wait_url_contain("/home") from pages.home_page import HomePage return HomePage(self.driver)6.6.2、register_page —— 注册页
核心方法有:输入姓名、用户名、密码、确认密码、点击“注册”按钮
from selenium.webdriver.common.by import By from base.base_page import BasePage class RegisterPage(BasePage): # 定位器 REAL_NAME_INPUT = (By.CSS_SELECTOR, "#name") USERNAME_INPUT = (By.CSS_SELECTOR,"#username") PASSWORD_INPUT = (By.CSS_SELECTOR,"#password") CONFIRM_PASSWORD_INPUT = (By.CSS_SELECTOR,"#rePassword") RETURN_LOGIN_LINK = (By.CSS_SELECTOR,"#root > div > div.content___1k5Ro > div.main___19HXK > div > form > div:nth-child(6) > a") REGISTER_BTN=(By.CSS_SELECTOR,"#root > div > div.content___1k5Ro > div.main___19HXK > div > form > button") # 输入姓名 def input_real_name(self,real_name): self.input_text(self.REAL_NAME_INPUT,real_name) return self # 输入用户名 def input_username(self,username): self.input_text(self.USERNAME_INPUT,username) return self # 输入密码 def input_password(self,password): self.input_text(self.PASSWORD_INPUT,password) return self # 确认密码 def input_confirm_password(self,confirm_password): self.input_text(self.CONFIRM_PASSWORD_INPUT,confirm_password) return self # 点击注册按钮(不跳转) def click_register(self): self.click(self.REGISTER_BTN) return self # 点击注册按钮并跳转 def click_register_and_wait(self): self.click(self.REGISTER_BTN) self.wait_url_contain("/login") return self # 返回登录链接 def click_login_link(self): self.click(self.RETURN_LOGIN_LINK) from pages.login_page import LoginPage return LoginPage(self.driver)6.6.3、home_page —— 首页
核心方法有:点击“创建问卷”按钮、点击“创建考试”按钮、查看“问卷记录”、查看“考试记录”
from selenium.webdriver.common.by import By from base.base_page import BasePage from pages.create_page import CreatePage from pages.projects_page import ProjectsPage class HomePage(BasePage): # 用户姓名定位器 USERNAME = (By.CSS_SELECTOR,"#sk-layout > div > div > section > div.ant-pro-layout-container > header.ant-layout-header.ant-pro-layout-header.ant-pro-layout-header-fixed-header.ant-pro-layout-header-mix.ant-pro-layout-header-fixed-header-action.ant-pro-layout-header-header > div > div.ant-pro-global-header-right-content > div > div > div > span > div") # 创建入口 CREATE_SURVEY = (By.CSS_SELECTOR,"#sk-layout > div > div > section > div.ant-pro-layout-container > main > div > div.ant-pro-grid-content > div > div > div > div.ant-col.ant-col-xs-24.ant-col-sm-24.ant-col-md-24.ant-col-lg-24.ant-col-xl-8 > div > div.ant-card-body > div > a:nth-child(1)") CREATE_EXAM =(By.CSS_SELECTOR,"#sk-layout > div > div > section > div.ant-pro-layout-container > main > div > div.ant-pro-grid-content > div > div > div > div.ant-col.ant-col-xs-24.ant-col-sm-24.ant-col-md-24.ant-col-lg-24.ant-col-xl-8 > div > div.ant-card-body > div > a:nth-child(2)") # 问卷记录 SURVEY_HISTORY = (By.CSS_SELECTOR,"#rc-tabs-8-tab-surveyHistory") # 考试记录 EXAM_HISTORY = (By.CSS_SELECTOR,"#rc-tabs-8-tab-examHistory") # 获取当前登录用户姓名 def get_user_name(self): return self.get_text(self.USERNAME) # 进入创建问卷页 def goto_create_survey(self): self.click(self.CREATE_SURVEY) self.wait_url_contain("/new?mode=survey") # 等待标题加载完毕 self.wait_util.wait_for_visible((By.CSS_SELECTOR, "#editorContent .title .ql-editor")) return CreatePage(self.driver) # 进入创建考试页 def goto_create_exam(self): self.click(self.CREATE_EXAM) self.wait_url_contain("/new?mode=exam") # 等待标题加载完毕 self.wait_util.wait_for_visible((By.CSS_SELECTOR, "#editorContent .title .ql-editor")) return CreatePage(self.driver) # 进入“我的项目”页 def goto_my_projects(self): self.click(self.MY_PROJECTS) self.wait_url_contain("/project") return ProjectsPage(self.driver) # 点击“问卷记录” def click_survey_history(self): self.click(self.SURVEY_HISTORY) return self # 点击“考试记录” def click_exam_history(self): self.click(self.EXAM_HISTORY) return self6.6.4、create_page —— 创建问卷/考试页
核心方法有:填写标题、填写标语、添加选项、设置选项内容、点击“保存”按钮
from selenium.webdriver.common.by import By from base.base_page import BasePage class CreatePage(BasePage): # 标题输入 TITLE_INPUT = (By.CSS_SELECTOR,"#editorContent .title .ql-editor") # 标语输入 SLOGAN_INPUT=(By.CSS_SELECTOR,"#editorContent .prefix .ql-editor") # 保存按钮 SAVE_BTN=(By.CSS_SELECTOR,"#editor > div.survey-main-panel > div.survey-main-panel-toolbar > div:nth-child(2) > div > button.ant-btn.ant-btn-primary.ant-btn-sm") # 左侧添加题目 QUESTION_BTN=(By.XPATH,"//div[contains(text(),'单选题')]") # 题目内容 QUESTION_CONTENT=(By.CSS_SELECTOR,"#editorContent .q-title-wrap .ql-editor") # 选项 OPTION=(By.CSS_SELECTOR, ".option .ql-editor") # 添加选项按钮 ADD_OPTION_BTN = (By.CSS_SELECTOR, ".q-operation a") # 填写标题 def fill_title(self,title): self.input_text(self.TITLE_INPUT,title) return self # 填写标语 def fill_slogan(self,slogan): self.input_text(self.SLOGAN_INPUT,slogan) return self # 点击保存按钮 def click_save(self): self.click(self.SAVE_BTN) return self # 点击左侧题目 def add_question(self): self.click(self.QUESTION_BTN) return self # 填写题目内容 def fill_question_content(self,question): self.input_text(self.QUESTION_CONTENT,question) return self # 填写选项一内容 def fill_option_01(self,option): options = self.driver.find_elements(*self.OPTION) options[0].send_keys(option) return self # 填写选项二内容 def fill_option_02(self,option): options = self.driver.find_elements(*self.OPTION) options[1].send_keys(option) return self # 添加新的选项 def click_add_option(self,text): self.click(self.ADD_OPTION_BTN) options = self.driver.find_elements(*self.OPTION) options[-1].send_keys(text)6.7、测试用例包testcases
6.7.1、登录成功测试用例
def Test_login_success(self, login_page): login_page.input_username(DEFAULT_USER["username"]) login_page.input_password(DEFAULT_USER["password"]) login_page.click_login_and_wait() # 判断是否成功跳转到对应的页面 assert "/home" in login_page.get_url()6.7.2、登录失败测试用例
# 登录失败 ---- 用户名为空 def Test_login_empty_username(self, login_page): login_page.input_username("") login_page.input_password(DEFAULT_USER["password"]) login_page.click_login() # 判断当前是否还在登录页 assert "/login" in login_page.get_url() # 判断是否有“用户名是必填项!”的错误信息 error_msg=login_page.get_error_message_username() assert error_msg == "用户名是必填项!" # 登录失败 ---- 密码为空 def Test_login_empty_password(self, login_page): login_page.input_username("liu1bo123") login_page.input_password("") login_page.click_login() assert "/login" in login_page.get_url() error_msg=login_page.get_error_message_password() assert error_msg == "密码是必填项!" # 登录失败 ---- 密码错误 def Test_login_wrong_password(self, login_page): login_page.input_username(DEFAULT_USER["username"]) login_page.input_password("654321") login_page.click_login() assert "/login" in login_page.get_url() error_msg=login_page.get_error_message_login() assert error_msg == "错误的用户名和密码"6.7.3、注册成功测试用例
# 注册成功 def Test_register_success(self,register_page): register_page.input_real_name("yhd") register_page.input_username("yhd123") register_page.input_password("123456") register_page.input_confirm_password("123456") register_page.click_register_and_wait() assert "/login" in register_page.get_url()6.7.4、注册失败测试用例
# 注册失败 ---- 姓名为空 def Test_register_empty_realname(self,register_page): register_page.input_real_name("") register_page.input_username("yhd123") register_page.input_password("123456") register_page.input_confirm_password("123456") register_page.click_register() assert "/register" in register_page.get_url() error_msg = register_page.get_error_message_realname() assert error_msg == "用户名是必填项!" # 注册失败 ---- 用户名为空 def Test_register_empty_username(self,register_page): register_page.input_real_name("yhd") register_page.input_username("") register_page.input_password("123456") register_page.input_confirm_password("123456") register_page.click_register() assert "/register" in register_page.get_url() error_msg = register_page.get_error_message_username() assert error_msg == "登录账号不能为空" # 注册失败 ---- 密码为空 def Test_register_empty_password(self,register_page): register_page.input_real_name("yhd") register_page.input_username("yhd123") register_page.input_password("") register_page.input_confirm_password("123456") register_page.click_register() assert "/register" in register_page.get_url() error_msg = register_page.get_error_message_password() assert error_msg == "密码是必填项!" # 注册失败 ---- 确认密码为空 def Test_register_empty_confirm(self,register_page): register_page.input_real_name("yhd") register_page.input_username("yhd123") register_page.input_password("123456") register_page.input_confirm_password("") register_page.click_register() assert "/register" in register_page.get_url() error_msg = register_page.get_error_message_confirm_password() assert error_msg == "请再次输入密码" # 注册失败 ---- 确认密码与密码不一致 def Test_register_mismatch(self,register_page): register_page.input_real_name("yhd") register_page.input_username("yhd123") register_page.input_password("123456") register_page.input_confirm_password("654321") register_page.click_register() assert "/register" in register_page.get_url() error_msg = register_page.get_error_message_confirm_password() assert error_msg == "两次密码不一致!" # 注册失败 ---- 账号已经存在,以用户名为标准 def Test_register_username_exists(self,register_page): register_page.input_real_name("mt") register_page.input_username(DEFAULT_USER["username"]) register_page.input_password(DEFAULT_USER["password"]) register_page.input_confirm_password(DEFAULT_USER["password"]) register_page.click_register() assert "/register" in register_page.get_url() error_msg = register_page.get_error_message_register() assert error_msg == "账号已存在"6.7.5、创建问卷成功测试用例
# 创建考试成功用例 def Test_create_exam_success(self,login_page): # 先登录 login_page.input_username(DEFAULT_USER["username"]) login_page.input_password(DEFAULT_USER["password"]) # 返回首页对象 home_page = login_page.click_login_and_wait() # 进入到创建问卷页 create_page = home_page.goto_create_exam() # 开始创建 create_page.fill_title("小学数学-01") create_page.fill_slogan("感谢您参与这次考试") create_page.add_question() create_page.click_question_content() create_page.fill_question_content("1+1=?") create_page.fill_option_01("A.1") create_page.fill_option_02("B.2") create_page.click_save() create_page.wait_success_msg() success_msg = create_page.get_success_msg() assert success_msg == "保存成功"6.7.6、创建考试成功测试用例
# 创建问卷成功用例 def test_create_survey_success(self,login_page): # 先登录 login_page.input_username(DEFAULT_USER["username"]) login_page.input_password(DEFAULT_USER["password"]) # 返回首页对象 home_page=login_page.click_login_and_wait() # 进入到创建问卷页 create_page=home_page.goto_create_survey() # 开始创建 create_page.fill_title("用户满意度调查-01") create_page.fill_slogan("感谢您的参与") create_page.add_question() create_page.click_question_content() create_page.fill_question_content("您对产品满意吗?") create_page.fill_option_01("A.满意") create_page.fill_option_02("B.一般") create_page.click_save() create_page.wait_success_msg() success_msg=create_page.get_success_msg() assert success_msg == "保存成功"七、接口测试
7.1、fiddler抓包分析
以简单抓包登录请求,然后分析登录成功/失败、重定向后的响应结果和信息为例
7.1.1、设置fiddler过滤器
在 Filters 标签页中,勾选 Use Filters,选择 Show only the following Hosts,并填入目标服务器地址 49.235.61.184。确保精准只获取该服务器的接口
7.1.2、fiddler检测密码是否明文
在登录页输入用户名和密码后,通过fiddler抓包工具抓取到登录接口的请求数据。结果发现密码经过加密,并未有泄露风险
八、性能测试
使用Postman、Jmeter测试工具对考试通问卷系统进行简单的性能测试。
九、allure生成测试报告
十、测试总结
问卷考试系统的基本功能正常运行,正常流程能够正确执行。
需优化“模板广场页面”中“搜模板”搜索不到指定模版问题。
交互体验良好:所有按钮点击响应迅速,页面渲染正常,无错别字、遮挡或显示异常。\n\n该系统的性能测试结果表明其在当前并发场景下表现优秀,能够满足正常需求。