基于flask+react搭建测试用例管理平台
发布日期:2022-02-24 01:06:51 浏览次数:13 分类:技术文章

本文共 11845 字,大约阅读时间需要 39 分钟。

基于flask+react搭建测试用例管理平台

平台介绍

在这里插入图片描述

平台目前功能介绍

  1. 工作台(账户动态,项目管理,组织管理,系统设置,测试分析等)
  2. 功能测试用例管理(本文只介绍此模块
  3. API自动化测试系统(接口自动化系统,场景配置,报告配置,用例管理等等)
  4. GUI自动化测试系统(UI自动化测试系统,场景配置,报告配置,用例管理等等,暂未开发完成
  5. 测试工具管理(测试脚本,小工具管理)
  6. 知识库(知识分享、问题收集)

因部门工作中所产出的测试用例数据难以收集和查阅,后又因TestLink界面不够友好,难以推动使用。开发了测试用例管理系统

测试用例管理模块主要逻辑流程为
新建测试计划 > 新建计划内上线功能或需求 > 创建测试用例(或上传测试用例支持Xmind导入,Excel导出等)> 执行测试 > 测试完成 > 更改需求状态 > 更改测试计划状态

效果展示-计划列表页

计划列表页

效果展示-计划详情页

计划详情页

使用到的技术栈 (测试用例管理)

后端

  1. 框架选择:FlaskTornado
  2. Python版本:3.6.5
  3. 数据库:MySQLRedis
  4. 异步任务处理:celery
  5. 服务进程管理:DockeruwsgiSupervisor
    Supervisor管理界面

前端

  1. 框架:Ant Design Pro(蚂蚁金服开源的基于 React 的中后台管理控制台的脚手架)
  2. nodejs版本:12.6.0
  3. react版本:16.7.0

后端服务介绍

  • requirements 文件
colorlogFlaskflask-apidocFlask-HTTPAuthFlask-Migrateflask-paginateFlask-RESTfulFlask-ScriptFlask-SQLAlchemyitsdangeroussqlalchemygeventmysqlclientpycryptodomePyMySQLredisrequestssshtunneluWSGIWerkzeugceleryconcurrentxlwtxmindparser
  • 服务结构
    Python版本:3.6.5
    编辑器:PyCharm 2018 1.3
    代码结构
  • 文件目录介绍
目录&文件 作用
Apis 各系统接口主要代码存放路径,用Blueprint分开接口, flask_restful 设计接口
Common 公共库,主要为应用工厂,日志,签名,celery任务消息队列处理,token认证等
Config 项目配置
Models 数据库相关model,用于ORM处理
DockerFile 用于构建Docker容器
runserver 项目启动入口
  • 配置文件 Config 的__init__.py文件
# -*- coding: utf-8 -*- # @File   : __init__.py# @Time   : 2020/1/3 下午3:26# @Author : bin.wang# @Detail : 配置文件from sqlalchemy import create_enginefrom datetime import timedeltafrom Common.log.logger import LogFile, Logfrom concurrent.futures import ThreadPoolExecutorimport redisimport osclass Config:    # 线程池, max_workers参数 不填默认为 CPU个数 * 5    threaded = True    executor = ThreadPoolExecutor()    # session过期时间    PERMANENT_SESSION_LIFETIME = timedelta(days=1)    SECRET_KEY = os.urandom(24)    # 为True ,无需 db.session.commit()    SQLALCHEMY_TRACK_MODIFICATIONS = False    # 上传文件大小限制 8M    MAX_CONTENT_LENGTH = 8 * 1024 * 1024    UPLOAD_FOLDER = '/log/api/file/'    ALLOWED_EXTENSIONS = {
'xmind'} # redis 配置 rds_host = 'localhost' rds_port = 6379 rds_db = 0 rds_pool_size = 300 redis_pool = redis.ConnectionPool(host=rds_host, port=rds_port, db=rds_db, max_connections=rds_pool_size) redis_db = redis.Redis(connection_pool=redis_pool) # celery任务队列服务端配置 CELERY_BROKER_URL = "redis://localhost:6379/0" CELERY_RESULT_BACKEND = "redis://localhost:6379/1" # 响应内容配置 success_status = "SUCCESS" success_message = "请求成功" fail_status = "FAIL" fail_message_body = "请求参数错误" fail_message_server = "请求异常" fail_message_path = "非法请求" fail_message_no_found = "查询为空" # 测试环境数据库配置 test_host = "xxxxxxxxxx" test_port = xxxxxxxxxx test_username = "xxxxxxxxxx" test_password = "xxxxxxxxxx" test_charset = "utf8" test_database = "xxxxxxxxxx" test_mysql_uri = create_engine('mysql+mysqldb://{}:{}@{}:{}/{}?charset=utf8'.format(test_username, test_password, test_host, test_port, test_database))class ProductionConfig(Config): # 生产 DEBUG = False AUTH_SALT = "xxxxxxxxxx" # token加盐字符串 HOSTNAME = 'xxxxxxxxxx' PORT = 'xxxxxxxxxx' DATABASE = 'xxxxxxxxxx' USERNAME = 'xxxxxxxxxx' PASSWORD = 'xxxxxxxxxx' DB_URI = 'mysql+mysqldb://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE) SQLALCHEMY_DATABASE_URI = DB_URI # 输出SQL语句 SQLALCHEMY_ECHO = False # 用例导出生成文件地址 EXCELPATH = "/xxxxxxxxxx/nginx/www/static/files/" # 日志配置 log_file_path = "/xxxxxxxxxx/log/api/flask/" log = LogFile(logger_name=__name__, debug=False, logfile_path=log_file_path).log()class DevelopmentConfig(Config): # 测试 DEBUG = True AUTH_SALT = "xxxxxxxxxx" HOSTNAME = 'xxxxxxxxxx' PORT = 'xxxxxxxxxx' DATABASE = 'xxxxxxxxxx' USERNAME = 'xxxxxxxxxx' PASSWORD = 'xxxxxxxxxx' DB_URI = 'mysql+mysqldb://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE) SQLALCHEMY_DATABASE_URI = DB_URI # 输出SQL语句 SQLALCHEMY_ECHO = True # 用例导出生成文件地址 EXCELPATH = "/xxxxxxxxxx/log/api/static/" # 控制台日志配置 log_file_path = "/xxxxxxxxxx/log/api/flask/" log = LogFile(logger_name=__name__, debug=False, logfile_path=log_file_path).log() # log = Log(logger_name=__name__, debug=True).logger_stream()config = {
"Dev": DevelopmentConfig, "Pro": ProductionConfig}
  • Config的 setting文件
from Config import configserverConfig = config["Pro"]## 这里控制服务启动哪个环境
  • runserver文件,应用启动入口
# -*- coding: utf-8 -*- # @File   : main# @Time   : 2019/9/16 上午10:06# @Author : bin.wang# @Detail :from gevent.pywsgi import WSGIServerfrom gevent import monkeymonkey.patch_all()from Common.Application import create_appfrom flask import request, jsonifyfrom Config.setting import serverConfigapp = create_app(serverConfig)log = serverConfig.log@app.errorhandler(404)def not_found(error):    return jsonify(status=serverConfig.fail_status, message=serverConfig.fail_message_path, data=request.path)@app.before_requestdef request_before():    log.info({
"request_path": request.path, "request_body": request.json, "request_args": request.args.to_dict()})if __name__ == '__main__': http_server = WSGIServer(('', 5000), app) http_server.serve_forever()

用例导入

Python xmindparser库实现,思路:

  1. 后端提供上传文件接口,xmindparser读取 xmind文件,转成字典
  2. 递归去寻找每一层,并拼接多级子模块为用例标题,(步骤结果可不填
  3. 把找到的用例加入列表,最终直接批量异步插入数据库
  4. 写入用例完成,删除上传的xmind文件,失败也删除
  • 示例:

    xmind文件:
    xmind测试用例

    上传成功:

    在这里插入图片描述

用例导出

Python xlwt库实现,思路:

  1. 后端接收需要导出的用例ID列表
  2. 查询出结果,根据需求归类(用于合并单元格计算),准备好数据列表
  3. 传递给封装好的Excel处理函数,并准备多套xlwt样式,根据不同主题展示不同内容
  4. 写入文件完成,生成静态文件路径给前端,前端下载

示例:用例导出结果

前端服务介绍

前端框架介绍

Ant Design Pro 是一个企业级中后台前端/设计解决方案,我们秉承 Ant Design 的设计价值观,致力于在设计规范和基础组件的基础上,继续向上构建,提炼出典型模板/业务组件/配套设计资源,进一步提升企业级中后台产品设计研发过程中的『用户』和『设计者』的体验。随着『设计者』的不断反馈,我们将持续迭代,逐步沉淀和总结出更多设计模式和相应的代码实现,阐述中后台产品模板/组件/业务场景的最佳实践,也十分期待你的参与和共建。

我们基于上述目标和提供了以下的典型模板,并据此构建了一套基于 React 的中后台管理控制台的脚手架,它可以帮助你快速搭建企业级中后台产品原型。

——来自

目录结构

├── config                   # umi 配置,包含路由,构建等配置├── mock                     # 本地模拟数据├── public│   └── favicon.png          # Favicon├── src│   ├── assets               # 本地静态资源│   ├── components           # 业务通用组件│   ├── e2e                  # 集成测试用例│   ├── layouts              # 通用布局│   ├── models               # 全局 dva model│   ├── pages                # 业务页面入口和常用模板│   ├── services             # 后台接口服务│   ├── utils                # 工具库│   ├── locales              # 国际化资源│   ├── global.less          # 全局样式│   └── global.js            # 全局 JS├── tests                    # 测试工具├── README.md└── package.json

部署生产环境

  • 后端:Jenkins部署代码,Supervisor重启服务
  • 前端:将构建后的文件作为静态资源部署在nginx中即可

Nginx配置

upstream baseService {    server base:9090 weight=1 max_fails=3 fail_timeout=30s;}upstream toolsService {    server xxxx:5000 weight=1 max_fails=3 fail_timeout=30s;}upstream Supervisor {    server xxxx:9001 weight=1 max_fails=3 fail_timeout=30s;}server {    server_name  localhost;    listen  80 default_server;    listen  [::]:80 default_server ipv6only=on;    gzip on;    gzip_min_length 1k;    gzip_comp_level 9;    gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml image/jpeg image/gif image/png;    gzip_vary on;    gzip_disable "MSIE [1-6]\.";    charset UTF-8;    access_log  /var/log/nginx/access.log  main;    root   /usr/share/nginx/html;    index  index.html index.htm;    location / {        try_files $uri $uri/ /index.html;    }    location /api/flask/ {        auth_request /auth;        auth_request_set $auth_status $upstream_status;        auth_request_set $user $upstream_http_x_forwarded_user;        error_page 401 = @error401;        proxy_pass  http://toolsService/api/;        proxy_redirect   off;        proxy_connect_timeout 600;        proxy_send_timeout 900;        proxy_read_timeout 900;        proxy_buffer_size 32k;        proxy_buffers 4 64k;        proxy_busy_buffers_size 128k;        proxy_redirect off;        proxy_hide_header Vary;        proxy_http_version 1.1;        proxy_set_header Upgrade $http_upgrade;        proxy_set_header Connection "Upgrade";        proxy_set_header Accept-Encoding '';        proxy_set_header Referer $http_referer;        proxy_set_header Cookie $http_cookie;        proxy_set_header Host $host;        proxy_set_header X-Real-IP $remote_addr;        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;        proxy_set_header X-Forwarded-Proto $scheme;        proxy_set_header X-Original-URI $request_uri;        proxy_next_upstream error timeout invalid_header http_404 http_500 http_502 http_503 http_504;    }    location /api/open/ {        proxy_pass http://baseService/open/;        proxy_connect_timeout 600;        proxy_send_timeout 900;        proxy_read_timeout 900;        proxy_buffer_size 32k;        proxy_buffers 4 64k;        proxy_busy_buffers_size 128k;        proxy_redirect off;        proxy_hide_header Vary;        proxy_http_version 1.1;        proxy_set_header Upgrade $http_upgrade;        proxy_set_header Connection "Upgrade";        proxy_set_header Accept-Encoding '';        proxy_set_header Referer $http_referer;        proxy_set_header Cookie $http_cookie;        proxy_set_header Host $host;        proxy_set_header X-Real-IP $remote_addr;        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;        proxy_set_header X-Forwarded-Proto $scheme;        proxy_set_header X-Original-URI $request_uri;        proxy_next_upstream error timeout invalid_header http_404 http_500 http_502 http_503 http_504;    }    location /api/admin/ {        auth_request /auth;        auth_request_set $auth_status $upstream_status;        auth_request_set $user $upstream_http_x_forwarded_user;        error_page 401 = @error401;        proxy_pass http://baseService/api/;        proxy_connect_timeout 600;        proxy_send_timeout 900;        proxy_read_timeout 900;        proxy_buffer_size 32k;        proxy_buffers 4 64k;        proxy_busy_buffers_size 128k;        proxy_redirect off;        proxy_hide_header Vary;        proxy_http_version 1.1;        proxy_set_header Upgrade $http_upgrade;        proxy_set_header Connection "Upgrade";        proxy_set_header Accept-Encoding '';        proxy_set_header Referer $http_referer;        proxy_set_header Cookie $http_cookie;        proxy_set_header Host $host;        proxy_set_header X-Real-IP $remote_addr;        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;        proxy_set_header X-Forwarded-Proto $scheme;        proxy_set_header X-Original-URI $request_uri;        proxy_next_upstream error timeout invalid_header http_404 http_500 http_502 http_503 http_504;    }    location = /auth {        internal;        proxy_pass http://baseService/auth/token;        proxy_connect_timeout 600;        proxy_send_timeout 900;        proxy_read_timeout 900;        proxy_buffer_size 32k;        proxy_buffers 4 64k;        proxy_busy_buffers_size 128k;        proxy_redirect off;        proxy_hide_header Vary;        proxy_http_version 1.1;        proxy_set_header Upgrade $http_upgrade;        proxy_set_header Connection "Upgrade";        proxy_set_header Accept-Encoding '';        proxy_set_header Referer $http_referer;        proxy_set_header Cookie $http_cookie;        proxy_set_header Host $host;        proxy_set_header X-Real-IP $remote_addr;        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;        proxy_set_header X-Forwarded-Proto $scheme;        proxy_set_header X-Original-URI $request_uri;        proxy_next_upstream error timeout invalid_header http_404 http_500 http_502 http_503 http_504;        proxy_pass_request_body off;        proxy_set_header Content-Type "application/json";        proxy_set_header Content-Length "";    }    location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|js|css)$ {        #设置上面定义的后缀文件缓存到浏览器的生存时间        expires   3d;        # #禁止缓存,每次都从服务器请求        # add_header Cache-Control no-store;    }    location @error401 {        default_type application/json;        return 401 '{"status":"FAIL","message":"登录超时, 请重新登录", "data":""}';    }    client_max_body_size 50M;    keepalive_timeout 10;}

写在后面

还没想好,哈哈哈

转载地址:https://blog.csdn.net/weixin_45877986/article/details/103857030 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:malloc、calloc和realloc区别
下一篇:TypeScript 备忘录:如何在 React 中完美运用?

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2024年04月10日 11时09分47秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章