网易首页 > 网易号 > 正文 申请入驻

测试用例越写越多管不过来,用Flask+Pytest造一个测试管理平台

0
分享至

随着项目规模的扩大,测试用例的数量和复杂度也会不断增加,如何高效地管理和执行这些测试用例成为一个挑战。本教程将手把手教你使用Flask和Pytest构建一个功能完整的自动化测试用例管理平台。

这个平台具备以下核心功能:

●集中管理测试用例

●创建和管理测试计划

●一键执行测试

●生成详细的测试报告

即使你是编程小白,跟着本教程一步步操作,也能成功搭建出这个平台!



一、环境准备

1.1 安装Python

确保你的电脑已安装Python 3.7或更高版本。打开命令行工具,输入以下命令检查:

python --version

如果未安装,请访问 Python 官网 下载安装。

1.2 创建项目目录

打开命令行,创建项目文件夹并进入:

mkdir test_platformcd test_platform

1.3 创建虚拟环境(推荐)

python -m venv venv

激活虚拟环境

①Windows 系统:

venv\Scripts\activate



②Mac/Linux 系统:

source venv/bin/activate

二、项目结构搭建

2.1 项目目录结构

test_platform/├── app.py # Flask 应用入口├── conftest.py # Pytest 配置文件├── requirements.txt # 依赖包列表├── templates/ # Flask 模板文件│ ├── base.html # 基础模板│ ├── index.html # 测试用例列表页│ ├── plan_list.html # 测试计划列表页│ └── report.html # 测试报告页├── static/ # 静态文件│ └── styles.css # 自定义样式├── test_cases/ # 测试用例目录│ ├── __init__.py│ ├── test_example.py # 示例测试用例│ └── test_api.py # API 测试用例├── test_plans/ # 测试计划存储目录│ └── example_plan.json # 示例测试计划└── reports/ # 测试报告存储目录

手动创建这些目录和文件,或使用以下命令(Windows 系统):

mkdir templates static test_cases test_plans reportstype nul > app.pytype nul > conftest.pytype nul > requirements.txt

三、安装依赖包

3.1 创建 requirements.txt

在 requirements.txt 文件中添加以下内容:

Flask==3.0.0pytest==7.4.3pytest-html==4.1.1Werkzeug==3.0.1

3.2 安装依赖

在命令行中执行:

pip install -r requirements.txt



等待安装完成,这可能需要几分钟时间。

四、编写核心代码

4.1 创建 Flask 应用入口(app.py)

在 app.py 中编写以下代码:

import osimport jsonimport subprocessfrom datetime import datetimefrom flask import Flask, render_template, request, redirect, url_for, jsonifyimport pytestapp = Flask(__name__)# 配置路径TEST_CASES_DIR = 'test_cases'TEST_PLANS_DIR = 'test_plans'REPORTS_DIR = 'reports'# 确保必要的目录存在for directory in [TEST_CASES_DIR, TEST_PLANS_DIR, REPORTS_DIR]: os.makedirs(directory, exist_ok=True)def get_all_test_cases(): """获取所有测试用例""" test_cases = [] ifnot os.path.exists(TEST_CASES_DIR): return test_cases for filename in os.listdir(TEST_CASES_DIR): if filename.startswith('test_') and filename.endswith('.py'): filepath = os.path.join(TEST_CASES_DIR, filename) with open(filepath, 'r', encoding='utf-8') as f: content = f.read() # 简单解析测试函数 test_functions = [line.strip() for line in content.split('\n') if line.strip().startswith('def test_')] for func in test_functions: func_name = func.split('(')[0].replace('def ', '') test_cases.append({ 'file': filename, 'name': func_name, 'path': f'{filename}::{func_name}' }) return test_cases@app.route('/')def index(): """首页 - 显示所有测试用例""" test_cases = get_all_test_cases() return render_template('index.html', test_cases=test_cases)@app.route('/plans')def plan_list(): """测试计划列表页""" plans = [] if os.path.exists(TEST_PLANS_DIR): for filename in os.listdir(TEST_PLANS_DIR): if filename.endswith('.json'): filepath = os.path.join(TEST_PLANS_DIR, filename) with open(filepath, 'r', encoding='utf-8') as f: plan_data = json.load(f) plan_data['filename'] = filename plans.append(plan_data) return render_template('plan_list.html', plans=plans)@app.route('/create_plan', methods=['POST'])def create_plan(): """创建测试计划""" plan_name = request.form.get('plan_name') selected_cases = request.form.getlist('test_cases') ifnot plan_name ornot selected_cases: return jsonify({'error': '计划名称和测试用例不能为空'}), 400 plan_data = { 'name': plan_name, 'created_at': datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'test_cases': selected_cases } filename = f"{plan_name.replace(' ', '_')}.json" filepath = os.path.join(TEST_PLANS_DIR, filename) with open(filepath, 'w', encoding='utf-8') as f: json.dump(plan_data, f, ensure_ascii=False, indent=2) return redirect(url_for('plan_list'))@app.route('/run_plan/

')def run_plan(plan_name): """执行测试计划""" filepath = os.path.join(TEST_PLANS_DIR, f"{plan_name}.json") ifnot os.path.exists(filepath): return"测试计划不存在", 404 with open(filepath, 'r', encoding='utf-8') as f: plan_data = json.load(f) # 生成报告文件名 report_name = f"report_{plan_name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.html" report_path = os.path.join(REPORTS_DIR, report_name) # 构建 pytest 命令 test_cases = [os.path.join(TEST_CASES_DIR, case) forcase in plan_data['test_cases']] pytest_args = test_cases + [ f'--html={report_path}', '--self-contained-html', '-v' ] # 执行测试 pytest.main(pytest_args) return redirect(url_for('view_report', report_name=report_name))@app.route('/reports/

')def view_report(report_name): """查看测试报告""" report_path = os.path.join(REPORTS_DIR, report_name) if os.path.exists(report_path): with open(report_path, 'r', encoding='utf-8') as f: report_content = f.read() return report_content return"报告不存在", 404@app.route('/reports_list')def reports_list(): """测试报告列表""" reports = [] if os.path.exists(REPORTS_DIR): for filename in os.listdir(REPORTS_DIR): if filename.endswith('.html'): filepath = os.path.join(REPORTS_DIR, filename) stat = os.stat(filepath) reports.append({ 'name': filename, 'created_at': datetime.fromtimestamp(stat.st_mtime).strftime('%Y-%m-%d %H:%M:%S'), 'size': f"{stat.st_size / 1024:.2f} KB" }) reports.sort(key=lambda x: x['created_at'], reverse=True) return render_template('report.html', reports=reports)if __name__ == '__main__': app.run(debug=True, host='0.0.0.0', port=5000)

4.2 创建 Pytest 配置文件(conftest.py)

在 conftest.py 中添加以下内容:

import pytestfrom datetime import datetime@pytest.fixture(scope='session')def test_config(): """测试配置信息""" return{ 'base_url': 'http://localhost:5000', 'timeout': 30, 'retry_times': 3 }@pytest.fixture(scope='function')def test_data(): """测试数据""" return{ 'username': 'test_user', 'password': 'test_password', 'email': 'test@example.com' }def pytest_configure(config): """Pytest 配置钩子""" config.addinivalue_line( "markers", "smoke: 冒烟测试用例" ) config.addinivalue_line( "markers", "regression: 回归测试用例" ) config.addinivalue_line( "markers", "api: API 测试用例" )def pytest_html_report_title(report): """自定义报告标题""" report.title = "自动化测试报告"def pytest_html_results_summary(prefix, summary, postfix): """自定义报告摘要""" prefix.extend([f"

测试时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S

☑️想涨薪、想走得更远,最稳妥的办法永远是投资自己的技能。

☑️可如果行业的天花板已经压到头顶,与其在原地内卷,不如借AI的东风换个赛道。

可以戳⬇️⬇️⬇️

✔️即可加入——>【个人号绿泡泡:annasea0928】领转行、入门、提升、需要的各种干货资料

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
“这辈子活到头了!”苏州电网清华男相亲被嫌弃,女方还发到网上炫耀,网友们讥讽道

“这辈子活到头了!”苏州电网清华男相亲被嫌弃,女方还发到网上炫耀,网友们讥讽道

蝴蝶花雨话教育
2026-10-27 00:05:14
曝光缅北电诈被悬赏杀害,反诈博主“徽剑”家属:俩彪形大汉堵到家,我们才签的谅解书

曝光缅北电诈被悬赏杀害,反诈博主“徽剑”家属:俩彪形大汉堵到家,我们才签的谅解书

时代周报
2026-10-27 19:07:09
佛州提前投票彻底“翻红”!单日碾压11.2%

佛州提前投票彻底“翻红”!单日碾压11.2%

经点星娱
2026-10-27 21:36:56
连续数月多次触摸女同事大腿,甚至将手伸入其上衣抚摸隐私部位,42岁摄影师被澳门警方拘捕

连续数月多次触摸女同事大腿,甚至将手伸入其上衣抚摸隐私部位,42岁摄影师被澳门警方拘捕

南方都市报
2026-10-28 08:28:04
一百万买一条命:判决书里,权力最大的人被隐去了名字

一百万买一条命:判决书里,权力最大的人被隐去了名字

卉姐
2026-10-27 11:50:47
城管砸烂“老兵烧烤”,叫嚣让他随便告,凌晨领导急电:闯大祸了

城管砸烂“老兵烧烤”,叫嚣让他随便告,凌晨领导急电:闯大祸了

悬案解密档案
2025-10-22 09:48:53
一名入伍才三个月的俄军逃兵,在乌东村落枪杀了五名熟睡的乌军无人机操作员,得手后端着枪一头扎进了乌克兰控制的哈尔科夫百万人口大城市

一名入伍才三个月的俄军逃兵,在乌东村落枪杀了五名熟睡的乌军无人机操作员,得手后端着枪一头扎进了乌克兰控制的哈尔科夫百万人口大城市

扶苏聊历史
2026-10-24 16:46:53
江苏一老人行走时突拿剪刀故意划伤路边车辆,没想到车主就在车内,行车记录仪拍下全程;车主当场报警,老人子女同意承担车辆全部维修费用

江苏一老人行走时突拿剪刀故意划伤路边车辆,没想到车主就在车内,行车记录仪拍下全程;车主当场报警,老人子女同意承担车辆全部维修费用

扬子晚报
2026-10-28 08:01:57
局势升级!美防长宣布反华言论,国防部出手,大批中国机构遭清除

局势升级!美防长宣布反华言论,国防部出手,大批中国机构遭清除

影孖看世界
2026-10-27 21:41:10
西甲很慌,姆巴佩摊上大事,失去的不止是中国市场,跨国资本也会敬而远之,天价年薪或也难保

西甲很慌,姆巴佩摊上大事,失去的不止是中国市场,跨国资本也会敬而远之,天价年薪或也难保

王新喜
2026-10-28 00:11:27
姆巴佩不当言论背后,才是我们该深思的东西!

姆巴佩不当言论背后,才是我们该深思的东西!

梦归秋辰
2026-10-27 19:38:14
能感觉到这位诺奖得主有一种脚趾扣地的尴尬

能感觉到这位诺奖得主有一种脚趾扣地的尴尬

老实人互帮互助联盟
2026-10-27 13:44:46
“没有帽子都不好意思猝死”:38岁教授去世,讣告全篇罗列头衔和项目,活生生的人被压成了一张成绩单!

“没有帽子都不好意思猝死”:38岁教授去世,讣告全篇罗列头衔和项目,活生生的人被压成了一张成绩单!

学术眺望
2026-10-27 22:45:03
杀害反诈博主吴恺的凶手赵冰正面照曝光!签署“刑事谅解书”的吴恺“亲人”拿了50万,和他没有血缘关系

杀害反诈博主吴恺的凶手赵冰正面照曝光!签署“刑事谅解书”的吴恺“亲人”拿了50万,和他没有血缘关系

火山詩话
2026-10-28 05:21:29
身家一年暴涨2000亿元!张一鸣赚的钱,和钟睒睒、马云、王健林的都不一样

身家一年暴涨2000亿元!张一鸣赚的钱,和钟睒睒、马云、王健林的都不一样

都市快报橙柿互动
2026-10-28 02:14:23
妻子坚决反对舒马赫安乐死,再卖8块名表筹款救夫,总价值约400万美元

妻子坚决反对舒马赫安乐死,再卖8块名表筹款救夫,总价值约400万美元

历史龙元阁
2026-10-28 07:25:13
德国专家:美国现在之所以处处避开中国,那就是可能美国已经意识到了,现在的中国早就不是美国能够随意掌控的了

德国专家:美国现在之所以处处避开中国,那就是可能美国已经意识到了,现在的中国早就不是美国能够随意掌控的了

扶苏聊历史
2026-10-27 18:06:49
姆巴佩到底说了啥?一个“玩笑”引发的连锁反应,或遭商业反噬

姆巴佩到底说了啥?一个“玩笑”引发的连锁反应,或遭商业反噬

汪星人哟
2026-10-27 08:32:57
需警惕:全民几乎不看电视、拒接陌生来电,这是一场双向的消耗

需警惕:全民几乎不看电视、拒接陌生来电,这是一场双向的消耗

云霄纪史观
2026-10-27 05:42:51
姆巴佩不用退代言费,还能起诉中国品牌要尾款

姆巴佩不用退代言费,还能起诉中国品牌要尾款

小小河
2026-10-28 02:16:26
2026-10-28 10:20:49
51Testing软件测试网 incentive-icons
51Testing软件测试网
中国软件测试人的精神家园
1668文章数 13285关注度
往期回顾 全部

科技要闻

M6芯片版14英寸MacBook Pro:15999元起

头条要闻

牛弹琴:博索纳罗败选携妻女"流亡"美国 卢拉气得大骂

头条要闻

牛弹琴:博索纳罗败选携妻女"流亡"美国 卢拉气得大骂

体育要闻

悲惨!杰威重伤倒下 最好的雷霆已成过去?

娱乐要闻

芒果遇到厉娜和许飞笑发财了!

财经要闻

解密 “速成车”:一辆车怎样更快造出来?

汽车要闻

纯电续航1003km 大五座SUV腾势N8正式开启预订

态度原创

数码
教育
家居
时尚
手机

数码要闻

苹果M6 iMac细节:2.5Gb网口藏进电源适配器

教育要闻

期中考后别急着问分:带孩子做张「卷面定位表」

家居要闻

2026建博会(广州) 公装联探展交流活动

「初代恶女」的选择:比起做母亲,我更想先做自己

手机要闻

REDMI K100上手,这价格、这体验还要什么自行车

无障碍浏览 进入关怀版