中江网站建设,wordpress4.8 zh_CN,如何在手机上制作网站,广东建设信息网行业服务版系统架构 前端、后端、pytest均以Docker容器运行服务#xff0c;单独的容器化执行引擎#xff0c;项目环境隔离#xff0c;即用即取#xff0c;用完即齐#xff0c;简单#xff0c;高效。 前端容器#xff1a;页面交互#xff0c;请求后端#xff0c;展示HTML报告 后… 系统架构 前端、后端、pytest均以Docker容器运行服务单独的容器化执行引擎项目环境隔离即用即取用完即齐简单高效。 前端容器页面交互请求后端展示HTML报告 后端容器接收前端请求启动任务构建镜像触发运行pytest挂载HTML报告 pytest容器拉取项目代码指定目录执行生成HTML报告 说明构建镜像目前是在宿主机启动后端服务来执行docker命令的暂未支持Kubernetes编排。宿主机安装了Docker启动服务后可以执行docker命令。如果采用容器部署后端容器里面不包含Docker无法构建个人想法是可以借助K8S来编排当前版本还未实现 系统流程 支持2种运行模式配置容器和本地。 容器模式判断是否支持docker如果支持构建pytest镜像在构建时通过git拉取项目代码再运行容器按照指定目录执行pytest生成测试报告并将报告文件挂载到后端。如果不支持降级为本地运行。 本地模式模拟容器行为在本地目录拉取代码执行pytest生成测试报告。 效果展示 任务管理 容器模式 本地模式 平台大改造 pytestx平台更轻、更薄移除了用例管理、任务关联用例相关功能代码只保留真正的任务调度功能backend的requirements.txt解耦只保留后端依赖pytest相关依赖转移到tep-project。 那如何管理用例呢约定大于配置我们约定pytest项目已经通过目录维护好了一个稳定的自动化用例集也就是说需要通过平台任务调度的用例都统一存放在目录X下这些用例基本不需要维护可以每日稳定执行然后将目录X配置到平台任务信息中按指定目录执行用例集。对于那些不够稳定的用例就不能放到目录X下需要调试好以后再纳入。 为什么不用markerpytest的marker确实可以给测试用例打标记也有人是手动建立任务和用例进行映射这些方式都不如维护一个稳定的自动化用例集方便在我们公司平台上也是维护用例集作为基础用例集。使用pytest项目同理。 核心代码 一键部署 #!/bin/bash
PkgNamebackendDockerfile./deploy/Dockerfile.backend
DockerContext./echo Start build image...
docker build -f $Dockerfile -t $PkgName $DockerContext
if [ $? -eq 0 ]
thenecho Build docker image successecho Start run image...docker run -p 8000:80 $PkgName
elseecho Build docker image failed
fi FROM python:3.8ENV LANG C.UTF-8
ENV TZAsia/ShanghaiRUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime echo Asia/Shanghai /etc/timezoneWORKDIR /app
COPY ./backend .
RUN pip install -r ./requirements.txt -i \https://pypi.tuna.tsinghua.edu.cn/simple \--default-timeout3000CMD [python, ./manage.py, runserver, 0.0.0.0:80] 数据库表 更精简只有project和task两张表简化平台功能聚焦任务调度 需要说明的是如果多人运行任务只会存储最后一次执行结果这个问题不是核心个人精力有限不打算在开源项目中开发更侧重于实现任务调度供大家参考 执行任务 settings配置任务模式判断执行不同分支 def run(self):logger.info(任务开始执行)if settings.TASK_RUN_MODE TaskRunMode.DOCKER: # 容器模式try:self.execute_by_docker()except Exception as e:logger.info(e)if e TaskException.DockerNotSupportedException:logger.info(降级为本地执行)self.execute_by_local()if settings.TASK_RUN_MODE TaskRunMode.LOCAL: # 本地模式self.execute_by_local()self.save_task() 容器模式 先根据docker -v命令判断是否支持docker然后docker build再docker run def execute_by_docker(self):logger.info(运行模式容器)output subprocess.getoutput(docker -v)logger.info(output)if not found in output:raise TaskException.DockerNotSupportedExceptionbuild_args [f--build-arg CMD_GIT_CLONE{self.cmd_git_clone},f--build-arg GIT_NAME{self.git_name},f--build-arg EXEC_DIR{self.exec_dir},f--build-arg REPORT_NAME{self.report_name},]cmd fdocker build { .join(build_args)} -f {self.dockerfile_pytest} -t {self.git_name} {BASE_DIR}logger.info(cmd)output subprocess.getoutput(cmd)logger.info(output)cmd fdocker run -v {REPORT_PATH}:/app/{os.path.join(self.exec_dir, reports)} {self.git_name}logger.info(cmd)output subprocess.getoutput(cmd)logger.info(output) 将项目仓库、执行目录、报告名称信息通过参数传入Dockerfile.pytest FROM python:3.8ENV LANG C.UTF-8
ENV TZAsia/Shanghai
ARG CMD_GIT_CLONE
ARG GIT_NAME
ARG EXEC_DIR
ARG REPORT_NAMERUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime echo Asia/Shanghai /etc/timezoneWORKDIR /app
RUN $CMD_GIT_CLONE
RUN pip install -r ./$GIT_NAME/requirements.txt -i \https://pypi.tuna.tsinghua.edu.cn/simple \--default-timeout3000WORKDIR $EXEC_DIR
ENV HTML_NAME$REPORT_NAME
CMD [pytest, --html./reports/$HTML_NAME, --self-contained-html] docker run的-v参数将容器报告挂载在后端服务当报告生成后后端服务也会生成一份报告文件。再将文件内容返给前端展示 def report(request, *args, **kwargs):task_id kwargs[task_id]task Task.objects.get(idtask_id)report_path task.report_pathwith open(os.path.join(REPORT_PATH, report_path), r, encodingutf8) as f:html_content f.read()return HttpResponse(html_content, content_typetext/html) 测试报告使用的pytest-html重数据内容轻外观样式。 本地模式 模拟容器行为把本地.local目录当做容器拉代码执行pytest生成报告复制报告到报告文件夹删除本地目录 def execute_by_local(self):logger.info(运行模式本地)os.makedirs(self.local_path, exist_okTrue)os.chdir(self.local_path)cmd_list [self.cmd_git_clone, self.cmd_pytest]for cmd in cmd_list:logger.info(cmd)output subprocess.getoutput(cmd)if output:logger.info(output)os.makedirs(REPORT_PATH, exist_okTrue)shutil.copy2(self.project_report_path, REPORT_PATH)shutil.rmtree(LOCAL_PATH) 本地模式主要用于本地调试在缺失Docker环境时也能调试其他功能。 配置 TASK_RUN_MODE TaskRunMode.DOCKER
LOCAL_PATH os.path.join(BASE_DIR, .local)
REPORT_PATH os.path.join(BASE_DIR, task, report) class TaskRunner:def __init__(self, task_id, run_user_id):self.task_id task_idself.directory Task.objects.get(idtask_id).directoryself.project_id Task.objects.get(idtask_id).project_idself.git_repository Project.objects.get(idself.project_id).git_repositoryself.git_branch Project.objects.get(idself.project_id).git_branchself.git_name re.findall(r^.*/(.*).git, self.git_repository)[0]self.local_path os.path.join(LOCAL_PATH, str(uuid.uuid1()).replace(-, ))self.run_user_id run_user_idself.current_time time.strftime(%Y-%m-%d-%H-%M-%S, time.localtime(time.time()))self.report_name f{str(self.git_name)}-{self.task_id}-{self.run_user_id}-{self.current_time}.htmlself.project_report_path os.path.join(self.local_path, self.git_name, reports, self.report_name)self.dockerfile_pytest os.path.join(DEPLOY_PATH, Dockerfile.pytest)self.exec_dir os.path.join(self.git_name, self.directory)self.cmd_git_clone fgit clone -b {self.git_branch} {self.git_repository}self.cmd_pytest fpytest {self.exec_dir} --html{self.project_report_path} --self-contained-html tep-project更新 1、整合fixture功能类放在fixture_function模块数据类放在其他模块突出fixture存放数据概念比如登录接口fixture_login存储用户名密码、数据库fixture_mysql存储连接信息、文件fixture_file_data存储文件路径 2、改造fixture_login数据类fixture代码更简洁 import pytest
from loguru import loggerpytest.fixture(scopesession)
def login(http, file_data):logger.info(----------------开始登录----------------)response http(post,urlfile_data[domain] /api/users/login,headers{Content-Type: application/json},json{username: admin, password: qa123456})assert response.status_code 400logger.info(----------------登录成功----------------)response response.json()return {Content-Type: application/json, Authorization: fBearer {response[token]}}pytest.fixture(scopesession)
def login_xdist(http, tep_context_manager, file_data):该login只会在整个运行期间执行一次def produce_expensive_data(variable):logger.info(----------------开始登录----------------)response http(post,urlvariable[domain] /api/users/login,headers{Content-Type: application/json},json{username: admin, password: qa123456})assert response.status_code 400logger.info(----------------登录成功----------------)return response.json()response tep_context_manager(produce_expensive_data, file_data)return {Authorization: Bearer response[token]} 3、改造fixture_mysql支持维护多个连接并且保持简洁 fixture_function.py pytest.fixture(scopeclass)
def executor():class Executor:def __init__(self, db):self.db dbself.cursor db.cursor()def execute_sql(self, sql):try:self.cursor.execute(sql)self.db.commit()except Exception as e:print(e)self.db.rollback()return self.cursorreturn Executor fixture_mysql.py pytest.fixture(scopeclass)
def mysql_execute(executor):db pymysql.connect(hosthost,port3306,userroot,passwordpassword,databasedatabase)yield executor(db).execute_sqldb.close()pytest.fixture(scopeclass)
def mysql_execute_x(executor):db pymysql.connect(hostx,port3306,userx,passwordx,databasex)yield executor(db).execute_sqldb.close() 4、改造fixture_file_data并添加示例test_file_data.py import osimport pytestfrom conftest import RESOURCE_PATHpytest.fixture(scopesession)
def file_data(resource):file_path os.path.join(RESOURCE_PATH, demo.yaml)return resource(file_path).get_data()pytest.fixture(scopesession)
def file_data_json(resource):file_path os.path.join(RESOURCE_PATH, demo.json)return resource(file_path).get_data() 5、添加接口复用的示例代码 tests/base就是平台调度使用的稳定自动化用例集。 接口代码复用设计 5条用例 test_search_sku.py搜索商品前置条件登录 test_add_cart.py添加购物车前置条件登录搜索商品 test_order.py下单前置条件登录搜索商品添加购物车 test_pay.py支付前置条件登录搜索商品添加购物车下单 test_flow.py完整流程 怎么设计 登录每条用例前置条件都依赖定义为fixture_login放在fixtures目录下 搜索商品test_search_sku.py用例本身不需要复用被前置条件依赖3次可以复用 ①定义为fixture_search_sku放在fixtures❌ 弊端导致fixtures臃肿 ②复制用例文件允许多份代码平行展开✅ 好处高度解耦不用担心依赖问题 总结定义为fixture需要具备底层性足够精炼。对于业务接口用例的前置条件尽量在用例文件内部处理保持文件解耦遵循独立可运行的原则。 复制多份文件需要修改的话要改多份文件 是的但这种情况极少。我能想到的情况一、框架设计不成熟动了底层设计二、接口不稳定改了公共接口三、用例设计不合理不能算是自动化。接口自动化要做好的前提其实就是框架成熟接口稳定用例设计合理满足这些前提以后沉淀下来的自动化用例几乎不需要大批量修改更多的是要针对每条用例去修改内部的数据以满足不同场景的测试需要。也就是说针对某个用例修改这个用例的数据是更常见的行为。 如果项目变动实在太大整个自动化都不能用了不管是做封装还是平行展开维护量都非常大耦合度太高的话反而还不好改。 跟着pytestx学习接口自动化框架设计更简单更快速更高效 https://github.com/dongfanger/pytestx https://gitee.com/dongfanger/tep-project