📋 文章目录
-
- [❤ 点击下方目录可跳转到对应章节](#❤ 点击下方目录可跳转到对应章节)
- [📝 项目背景](#📝 项目背景)
- [☁️ 项目简介](#☁️ 项目简介)
-
- [✨ 项目有哪些功能](#✨ 项目有哪些功能)
- [🔍 每个功能如何使用](#🔍 每个功能如何使用)
- [🎯 测试计划](#🎯 测试计划)
- [⏳ 测试工具](#⏳ 测试工具)
- [📅 测试类型与方法](#📅 测试类型与方法)
- [🤖 自动化测试](#🤖 自动化测试)
-
- [1️⃣ Web测试用例编写](#1️⃣ Web测试用例编写)
- [❤ 登录页面的测试用例](#❤ 登录页面的测试用例)
- [❤ "问卷和考试"文件夹测试用例](#❤ “问卷和考试”文件夹测试用例)
- [❤ 填写问卷测试用例](#❤ 填写问卷测试用例)
- [❤ 填写考试测试用例](#❤ 填写考试测试用例)
- [❤ 结果统计测试用例](#❤ 结果统计测试用例)
- [2️⃣ 自动化代码编写------测试用例的核心功能](#2️⃣ 自动化代码编写——测试用例的核心功能)
-
- [🔧 (1)目录图](#🔧 (1)目录图)
- [📋 (2)解释目录中的文件用处](#📋 (2)解释目录中的文件用处)
- [📋 (3)代码部分](#📋 (3)代码部分)
-
- [🔐 ① 登录页面](#🔐 ① 登录页面)
-
- [✅ 检查页面正常加载的效果图](#✅ 检查页面正常加载的效果图)
- [✅ 检查成功登录](#✅ 检查成功登录)
- [❌ 检查失败登录](#❌ 检查失败登录)
- [📃 ② 新建"问卷和考试"文件夹](#📃 ② 新建“问卷和考试”文件夹)
- [📃 ③在"问卷和考试"文件夹中新建问卷,填写问卷并提交](#📃 ③在“问卷和考试”文件夹中新建问卷,填写问卷并提交)
- [👆 ④在"问卷和考试"文件夹中新建考试文件,填写考试并提交`](#👆 ④在“问卷和考试”文件夹中新建考试文件,填写考试并提交`)
- [👆 ⑤总测试](#👆 ⑤总测试)
❤ 点击下方目录可跳转到对应章节
📝 项目背景
以前要是想搞个问卷调查或者在线考试,你得自己发链接、收答案、手动判分、再一个个算成绩。题目多了以后,分类、查找、统计成绩都特别费劲。
卷王问卷考试系统把这些麻烦事儿全都包办了------你只需要新建一个"问卷和考试"文件夹,在里面新建问卷、考试或者题库,点一下发布,系统就会自动帮你渲染题目、收集答案、自动判分、统计成绩,还能把数据存好归档。
对于学编程的人来说,这个系统是个很好的练手项目。它包含了用户登录、文件夹管理、问卷增删改查、考试发布和提交、题库管理、自动判分、后台权限控制、前端页面渲染等等 Web 开发的常见环节。从零开始做一个这样的系统,你能真正明白一个网站从用户点击到页面加载到底是怎么跑的,数据怎么存、后端怎么响应、前端怎么把数据显示出来。
具体开发的时候,大致分几步:
第一步,搞清楚需求,设计数据库,想好用户、文件夹、问卷、考试、题库、题目、提交记录这些数据之间的关系。
第二步,写后端接口,比如用户登录注册、文件夹管理、问卷管理、考试管理、题库管理、提交答案和自动判分等功能。
第三步,写前端页面,把后端返回的数据展示成文件夹列表、问卷详情、答题页面、成绩页面等等。
第四步,前后端联调测试,确保登录、新建文件夹、在文件夹里新建问卷并填写提交、新建考试并填写提交、新建题库等关键流程都能正常运行。
总而言之,卷王问卷考试系统的核心价值,在于将出题、组卷、发布、作答、判分、统计六个环节实现流程自动化。
>
☁️ 项目简介
✨ 项目有哪些功能
❤ 用户登录
❤ 用户信息展示
❤ 新建"问卷和考试"文件夹
❤ 在"问卷和考试"文件夹中新建问卷
❤ 填写问卷并提交
❤ 在"问卷和考试"文件夹中新建考试文件
❤ 填写考试文件并提交
❤ 新建题库与题库管理
❤ 问卷/考试结果统计
❤ 未登录状态下的权限限制
🔍 每个功能如何使用
💖用户登录 :在登录页输入正确的账号和密码后,后端验证通过后返回用户登录凭证 Token,前端保存 Token 并自动跳转到首页。此时首页会显示用户相关信息。
💖用户信息展示 :进入首页,前端请求 currentUser、userOverview 等接口,在首页正中展示头像、昵称、问卷数、考试数等。
💖新建"问卷和考试"文件夹 :在首页中,点击"我的项目按钮",进入我的项目页面,在项目页面中点击"新建"下拉框中的"新建文件夹"就可以执行创建。
💖在"问卷和考试"文件夹中新建问卷 :点击问卷和考试文件夹中的新建按钮,点击下拉框中的"问卷调查"按钮,可以手动添加题目,也可以通过点击文本导入按钮把文本导入进来充当题目。
💖填写问卷调查并提交 :打开已创建好的问卷,点击数据按钮,点击添加数据按钮,逐题作答,点击提交,即可提交成功。
💖在"问卷和考试"文件夹中新建考试文件 :点击问卷和考试文件夹中的新建按钮,点击下拉框中的"在线考试"按钮,可以手动添加考试题目,也可以通过点击文本导入按钮把文本导入进来充当考试题目。
💞 填写考试并提交 :打开已创建好的问卷,点击数据按钮,点击添加数据按钮,逐题作答,点击提交,即可提交成功。
💞 新建题库与题库管理 :回到系统登录成功后的页面,点击左侧导航栏的我的题库,点击新建,输入题库名称、题库标签、题库分类、题库类型,点击确定,题库创建成功。
💖问卷/考试结果统计:进入创建的问卷和考试文件夹,点击创建好的问卷或考试项目,点击报表,就能看到结果统计。
💖未登录状态下的权限限制:未登录时,不能查看登录成功页的所有信息。
🎯 测试计划
| 🎯 功能 | 👨💻 后端开发 | 👩💻 前端开发 | 📅 提测日期 | 🧑🔬 测试 | 📅 测试日期 | 🏆 测试结果 |
|---|---|---|---|---|---|---|
| 🔐 登陆界面 | 星星码 | 星星码 | 10.9 | 星星码 | 10.9 | 🟢 通过 |
| 📁 新建"问卷和考试"文件夹 | 星星码 | 星星码 | 10.10 | 星星码 | 10.10 | 🟢 通过 |
| 📝 文件夹中新建问卷与填写提交 | 星星码 | 星星码 | 10.11 | 星星码 | 10.11 | 🟢 通过 |
| 📄 文件夹中新建考试与填写提交 | 星星码 | 星星码 | 10.12 | 星星码 | 10.12 | 🟢 通过 |
| 📚 题库新建与管理 | 星星码 | 星星码 | 10.12 | 星星码 | 10.12 | 🟢 通过 |
| 📊 结果统计页 | 星星码 | 星星码 | 10.13 | 星星码 | 10.13 | 🟢 通过 |
⏳ 测试工具
💙接口测试工具:Postman、浏览器自带的F12(Network面板),作用➡️页面显示不对时,用它直接看后端返回的数据对不对
💙自动化测试工具(代替人力点点点):Selenium,作用➡️写代码让机器自动去点网页
💙性能测试工具:JMeter,作用➡️测试大量用户同时访问时,服务器会不会卡死或崩溃
💙Excel:作用➡️记录Bug、测试计划
💙Xmind:作用➡️编写测试用例
💙PyCharmCommunityEdition2025软件:作用➡️在该软件上配置python环境后,写Selenium代码来测试
📅 测试类型与方法
⚝ 功能测试:覆盖了登录、新建"问卷和考试"文件夹、文件夹中新建问卷、填写问卷提交、文件夹中新建考试、填写考试提交、题库新建与管理等核心模块,发现并跟踪了多个 Bug。
⚝ 性能测试:覆盖了登录、文件夹列表、文件夹下项目列表、提交问卷、提交考试、结果统计等核心接口。
⚝ 自动化测试:覆盖了登录成功、新建"问卷和考试"文件夹、在文件夹中新建问卷、填写问卷并提交、新建考试文件、填写考试并提交、新建题库等流程。
🤖 自动化测试
1️⃣ Web测试用例编写
❤ 登录页面的测试用例

❤ "问卷和考试"文件夹测试用例

❤ 填写问卷测试用例

❤ 填写考试测试用例

❤ 结果统计测试用例

2️⃣ 自动化代码编写------测试用例的核心功能
🔧 (1)目录图

📋 (2)解释目录中的文件用处
🧰 1. Common(公共装备库)
• 📍 定位:存放所有测试模块共用的底层代码,避免重复造轮子
📄 Utils.py(核心工具类):
这里封装了 Selenium 的基础操作,例如:
🍭打开浏览器
🍭智能等待(隐式等待implicitly_wait)
🍭截图保存
📁 images/(媒体素材库):
📍 定位:存放自动化测试过程中需要的静态文件。例如:
🍭用例测试成功或失败时自动生成的截图
🧪 2. Tests(测试业务层)
📍 定位:存放具体业务模块的测试用例和页面对象,对应之前梳理的"登录、列表、详情、编辑"测试用例。
🍎QuestionnaireLogin.py ➡️ 输入账号 -> 输入密码 -> 点击"登录"按钮。
🍎NewQuestionnaire.py ➡️ 新建"问卷和考试"文件夹。
🍎NewQuestionnaire.py、SubmitQuestionnaire.py ➡️ 在"问卷和考试"文件夹中新建问卷、填写问卷、提交问卷
🍎NewExamProject.py、SubmitExamProject.py ➡️ 在"问卷和考试"文件夹中新建考试文件、填写考试、提交考试。
🚦 3. RunTest.py(总调度中心)
• 📍 定位:自动化测试的"一键启动按钮"和"导航总控"。
📋 (3)代码部分
🔐 ① 登录页面
✅ 检查页面正常加载的效果图

✅ 检查成功登录
代码:
bash
import time
from selenium.webdriver.common.by import By
from Common.Utils import QuestionnaireDriver
class QuestionnaireLogin:
def __init__(self):
self.url="http://49.235.61.184:8080/user/login"
self.driver=QuestionnaireDriver.driver
self.driver.get(self.url)
def LoginSuccessTest(self):
self.driver.find_element(By.CSS_SELECTOR,"#username").send_keys("彭杰")
self.driver.find_element(By.CSS_SELECTOR,"#password").send_keys("3511697")
self.driver.find_element(By.CSS_SELECTOR, "#root > div > div.content___2zk1- > div.main___x4OjT > div > form > button").click()
time.sleep(3)
self.driver.find_element(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")
QuestionnaireDriver.getScreenshot()
#login=QuestionnaireLogin()
#login是类实例化出来的一个对象,那么下边就可以直接调用对象里面的LoginSuccessTest()
#login.LoginSuccessTest()
登录成功效果图

❌ 检查失败登录
效果图:

📃 ② 新建"问卷和考试"文件夹
代码:
bash
import time
from selenium.webdriver.common.by import By
from Common.Utils import QuestionnaireDriver
#from Tests.QuestionnaireLogin import login
class Questionnaire:
def __init__(self):
self.url="http://49.235.61.184:8080/user/login"
self.driver=QuestionnaireDriver.driver
#self.driver.get(self.url)
def folder(self):
self.driver.get("http://49.235.61.184:8080/project")
self.driver.find_element(By.CSS_SELECTOR,"#sk-layout > div > div > section > div.ant-pro-layout-container > main > div > div.ant-page-header.ant-pro-page-container-warp-page-header.ant-pro-page-container-warp-page-header.ant-page-header-has-breadcrumb.ant-page-header-ghost > div.ant-page-header-heading > span > div > div > button > span:nth-child(2)").click()
time.sleep(3)
#文本定位
self.driver.find_element(By.XPATH,"//span[text()='新建文件夹']").click()
#绝对路径定位
self.driver.find_element(By.CSS_SELECTOR,"#name").send_keys("问卷和考试")
time.sleep(3)
#属性定位
self.driver.find_element(By.XPATH,"//div[contains(@class,'ant-modal-footer')]//button[contains(@class,'ant-btn-primary')]").click()
time.sleep(3)
QuestionnaireDriver.getScreenshot()
#在已创建好的文件夹中创建问卷
def NewQuestionnaire(self):
#属性定位
#self.driver.get("http://49.235.61.184:8080/project")
self.driver.find_element(By.XPATH,"//button[@title='问卷和考试']").click()
time.sleep(3)
#文件夹里的新建按钮没有id属性,那就不能用属性定位,改用xpath文本定位
self.driver.find_element(By.XPATH,"//span[text()='新建']").click()
time.sleep(10)
self.driver.find_element(By.XPATH,"//span[@class='ant-dropdown-menu-title-content']").click()
time.sleep(15)
#click()返回的是空,对空不能操作
element=self.driver.find_element(By.XPATH,"//p[text()='请输入标题']")
element.click()
element.send_keys("评价学校校园环境")
time.sleep(3)
self.driver.find_element(By.XPATH,"//div[text()='单选题']").click()
time.sleep(3)
element2=self.driver.find_element(By.XPATH,"//p[text()='单选题']")
element2.click()
element2.send_keys("你觉得学校的校园环境优美吗?")
element3=self.driver.find_element(By.XPATH, "//p[text()='选项1']")
element3.click()
element3.send_keys("√")
element4 = self.driver.find_element(By.XPATH, "//p[text()='选项2']")
element4.click()
element4.send_keys("×")
self.driver.find_element(By.XPATH,"//span[text()='保 存']").click()
time.sleep(3)
QuestionnaireDriver.getScreenshot()
# def SubmitQuestionnaire(self):
# #填写问卷并提交
# self.driver.get("http://49.235.61.184:8080/project")
# self.driver.find_element(By.XPATH, "//button[@title='问卷和考试']").click()
# time.sleep(3)
# self.driver.find_element(By.XPATH,"//span[@class='survey-title']").click()
# self.driver.find_element(By.XPATH,"//span[text()='数据']").click()
# self.driver.find_element(By.XPATH, "//a[text()='添加数据']").click()
# self.driver.find_element(By.XPATH, "//input[@class='ant-radio-input']").click()
# time.sleep(3)
# QuestionnaireDriver.getScreenshot()
# self.driver.find_element(By.XPATH, "//span[text()='提 交']").click()
# QuestionnaireDriver.getScreenshot()
# time.sleep(2)
#naire=Questionnaire()
#login.LoginSuccessTest()
#naire.folder()
#naire.NewQuestionnaire()
#naire.SubmitQuestionnaire()
效果图:

📃 ③在"问卷和考试"文件夹中新建问卷,填写问卷并提交
代码:
bash
import time
from selenium.webdriver.common.by import By
from Common.Utils import QuestionnaireDriver
#from Tests.QuestionnaireLogin import login
class Questionnaire:
def __init__(self):
self.url="http://49.235.61.184:8080/user/login"
self.driver=QuestionnaireDriver.driver
#self.driver.get(self.url)
def folder(self):
self.driver.get("http://49.235.61.184:8080/project")
self.driver.find_element(By.CSS_SELECTOR,"#sk-layout > div > div > section > div.ant-pro-layout-container > main > div > div.ant-page-header.ant-pro-page-container-warp-page-header.ant-pro-page-container-warp-page-header.ant-page-header-has-breadcrumb.ant-page-header-ghost > div.ant-page-header-heading > span > div > div > button > span:nth-child(2)").click()
time.sleep(3)
#文本定位
self.driver.find_element(By.XPATH,"//span[text()='新建文件夹']").click()
#绝对路径定位
self.driver.find_element(By.CSS_SELECTOR,"#name").send_keys("问卷和考试")
time.sleep(3)
#属性定位
self.driver.find_element(By.XPATH,"//div[contains(@class,'ant-modal-footer')]//button[contains(@class,'ant-btn-primary')]").click()
time.sleep(3)
QuestionnaireDriver.getScreenshot()
#在已创建好的文件夹中创建问卷
def NewQuestionnaire(self):
#属性定位
#self.driver.get("http://49.235.61.184:8080/project")
self.driver.find_element(By.XPATH,"//button[@title='问卷和考试']").click()
time.sleep(3)
#文件夹里的新建按钮没有id属性,那就不能用属性定位,改用xpath文本定位
self.driver.find_element(By.XPATH,"//span[text()='新建']").click()
time.sleep(10)
self.driver.find_element(By.XPATH,"//span[@class='ant-dropdown-menu-title-content']").click()
time.sleep(15)
#click()返回的是空,对空不能操作
element=self.driver.find_element(By.XPATH,"//p[text()='请输入标题']")
element.click()
element.send_keys("评价学校校园环境")
time.sleep(3)
self.driver.find_element(By.XPATH,"//div[text()='单选题']").click()
time.sleep(3)
element2=self.driver.find_element(By.XPATH,"//p[text()='单选题']")
element2.click()
element2.send_keys("你觉得学校的校园环境优美吗?")
element3=self.driver.find_element(By.XPATH, "//p[text()='选项1']")
element3.click()
element3.send_keys("√")
element4 = self.driver.find_element(By.XPATH, "//p[text()='选项2']")
element4.click()
element4.send_keys("×")
self.driver.find_element(By.XPATH,"//span[text()='保 存']").click()
time.sleep(3)
QuestionnaireDriver.getScreenshot()
# def SubmitQuestionnaire(self):
# #填写问卷并提交
# self.driver.get("http://49.235.61.184:8080/project")
# self.driver.find_element(By.XPATH, "//button[@title='问卷和考试']").click()
# time.sleep(3)
# self.driver.find_element(By.XPATH,"//span[@class='survey-title']").click()
# self.driver.find_element(By.XPATH,"//span[text()='数据']").click()
# self.driver.find_element(By.XPATH, "//a[text()='添加数据']").click()
# self.driver.find_element(By.XPATH, "//input[@class='ant-radio-input']").click()
# time.sleep(3)
# QuestionnaireDriver.getScreenshot()
# self.driver.find_element(By.XPATH, "//span[text()='提 交']").click()
# QuestionnaireDriver.getScreenshot()
# time.sleep(2)
#naire=Questionnaire()
#login.LoginSuccessTest()
#naire.folder()
#naire.NewQuestionnaire()
#naire.SubmitQuestionnaire()
bash
import time
from selenium.webdriver.common.by import By
from Common.Utils import QuestionnaireDriver
#from Tests.QuestionnaireLogin import login
class SubmitQuestionnaire:
def __init__(self):
self.url = "http://49.235.61.184:8080/user/login"
self.driver = QuestionnaireDriver.driver
#self.driver.get(self.url)
def SubmitQuestionnaire(self):
#填写问卷并提交
self.driver=QuestionnaireDriver.driver
self.driver.get("http://49.235.61.184:8080/project")
time.sleep(6)
self.driver.find_element(By.XPATH, "//button[@title='问卷和考试']").click()
time.sleep(6)
self.driver.find_element(By.XPATH,"//span[@class='survey-title']").click()
self.driver.find_element(By.XPATH,"//span[text()='数据']").click()
self.driver.find_element(By.XPATH, "//a[text()='添加数据']").click()
self.driver.find_element(By.XPATH, "//input[@class='ant-radio-input']").click()
time.sleep(3)
QuestionnaireDriver.getScreenshot()
self.driver.find_element(By.XPATH, "//span[text()='提 交']").click()
QuestionnaireDriver.getScreenshot()
time.sleep(2)
# naire=SubmitQuestionnaire()
# login.LoginSuccessTest()
# naire.SubmitQuestionnaire()
效果图:


👆 ④在"问卷和考试"文件夹中新建考试文件,填写考试并提交`
bash
import time
from selenium.webdriver.common.by import By
from Common.Utils import QuestionnaireDriver
#from Tests.QuestionnaireLogin import login
class NewExamProject:
def __init__(self):
self.url = "http://49.235.61.184:8080/user/login"
self.driver = QuestionnaireDriver.driver
#self.driver.get(self.url)
def NewExamProject(self):
#属性定位
self.driver.get("http://49.235.61.184:8080/project")
time.sleep(5)
self.driver.find_element(By.XPATH,"//button[@title='问卷和考试']").click()
time.sleep(3)
# 文件夹里的新建按钮没有id属性,那就不能用属性定位,改用xpath文本定位
self.driver.find_element(By.XPATH, "//span[text()='新建']").click()
time.sleep(5)
self.driver.find_element(By.XPATH,"//span[@class='ant-dropdown-menu-title-content']").click()
time.sleep(15)
element1=self.driver.find_element(By.XPATH,"//div[@class='ql-editor' and @data-gramm='false']")
element1.click()
#考试名称
element1.send_keys("数学考试")
time.sleep(3)
element5=self.driver.find_element(By.XPATH,"//div[@class='menu-group-item']").click()
element2 = self.driver.find_element(By.XPATH, "//p[text()='单选题']")
element2.click()
time.sleep(3)
element2.send_keys("函数y=x平方的导数是?")
time.sleep(3)
element3 = self.driver.find_element(By.XPATH, "//p[text()='选项1']")
element3.click()
element3.send_keys("2x")
element4 = self.driver.find_element(By.XPATH, "//p[text()='选项2']")
element4.click()
element4.send_keys("×的平方")
self.driver.find_element(By.XPATH, "//span[text()='保 存']").click()
time.sleep(3)
QuestionnaireDriver.getScreenshot()
time.sleep(3)
# exam=NewExamProject()
# login.LoginSuccessTest()
# exam.NewExamProject()
bash
import time
from selenium.webdriver.common.by import By
from Common.Utils import QuestionnaireDriver
#from Tests.QuestionnaireLogin import login
class SubmitExamProject:
def __init__(self):
self.url = "http://49.235.61.184:8080/user/login"
self.driver = QuestionnaireDriver.driver
#self.driver.get(self.url)
def SubmitExamProject(self):
#填写问卷并提交
self.driver=QuestionnaireDriver.driver
self.driver.get("http://49.235.61.184:8080/project")
time.sleep(6)
self.driver.find_element(By.XPATH, "//button[@title='问卷和考试']").click()
time.sleep(3)
self.driver.find_element(By.XPATH,"//span[@class='survey-title' and @title='数学考试']").click()
self.driver.find_element(By.XPATH,"//span[text()='数据']").click()
self.driver.find_element(By.XPATH, "//a[text()='添加数据']").click()
time.sleep(3)
self.driver.find_element(By.XPATH, "//input[@class='ant-radio-input']").click()
time.sleep(7)
self.driver.find_element(By.XPATH, "//span[text()='提 交']").click()
QuestionnaireDriver.getScreenshot()
time.sleep(2)
QuestionnaireDriver.getScreenshot()
# naire=SubmitExamProject()
# login.LoginSuccessTest()
# naire.SubmitExamproject()
效果图


👆 ⑤总测试
代码:
bash
#5个文件都要测试到,那么我们就要把5个文件都导入进来用
from Tests import QuestionnaireLogin #在浏览器中打开了登录页面
from Tests import NewQuestionnaire
from Tests import SubmitQuestionnaire
from Tests import NewExamProject
from Tests import SubmitExamProject
if __name__ =="__main__":
QuestionnaireLogin.QuestionnaireLogin().LoginSuccessTest()#输入账号密码,成功登录
NewQuestionnaire.Questionnaire().folder()#打开项目页,创建文件夹
NewQuestionnaire.Questionnaire().NewQuestionnaire()#文件夹里新建问卷
SubmitQuestionnaire.SubmitQuestionnaire().SubmitQuestionnaire()#测试提交问卷成功
NewExamProject.NewExamProject().NewExamProject()#文件夹里新建考试项目
SubmitExamProject.SubmitExamProject().SubmitExamProject()