三十一、【高级特性篇】接口用例参数化与关联:实现上下文数据传递

    • 前言
      • 准备工作
      • 第一部分:后端数据模型调整
        • 1. 升级 `TestCase` 模型
        • 2. 生成并应用数据库迁移
        • 3. 更新 `TestCaseSerializer`
      • 第二部分:后端测试执行器强化
        • 1. 修改 `execute_api_test_case` 函数
        • 2. 修改 Celery 任务 (`api/tasks.py`)
        • 1. 更新 `api/testcase.ts` 中的类型定义
        • 2. 大改 `TestCaseEditView.vue`
      • 第四部分:全面测试与验证
    • 总结

前言

在接口测试中,用例之间往往存在依赖关系:一个接口的响应数据(例如,用户 ID、认证 Token、订单号)需要作为下一个接口的请求参数。目前,测试平台还没有实现这种上下游数据传递,导致测试用例的复用性低、维护成本高。

本文的目标是:

在测试平台中实现参数提取 (Extraction) 和参数注入 (Injection) 机制,使测试用例之间能够自动传递数据,从而实现真正的端到端自动化测试。

在这里插入图片描述

准备工作

  1. 前端项目就绪: test-platform/frontend 项目可以正常运行 (npm run dev)。
  2. 后端 API 运行中: Django 后端服务运行。
  3. TestCase 模型已存在。
  4. requests 库和 jsonpath-ng 已安装在后端虚拟环境。
  5. Celery 和 Redis 已配置并运行。
  6. Element Plus 集成完毕。

第一部分:后端数据模型调整

修改 TestCase 模型,增加字段来存储提取和注入的规则。

1. 升级 TestCase 模型

打开 test-platform/api/models.py
TestCase 模型中,新增 extract_params 字段。
在这里插入图片描述

# test-platform/api/models.py
# ... (其他导入和模型定义) ...class TestCase(BaseModel):# ... (原有字段,如 module, priority, case_type, request_method, request_url 等) ...# --- 新增:变量提取和参数注入规则 ---extract_params = models.TextField(null=True, blank=True, default='[]', verbose_name="参数提取规则 (JSON格式)")# ...
2. 生成并应用数据库迁移
# 在 test-platform 目录下
python manage.py makemigrations api
python manage.py migrate api
3. 更新 TestCaseSerializer

打开 test-platform/api/serializers.py,将新的 extract_params 字段添加到 TestCaseSerializerfields 列表中。
在这里插入图片描述

# test-platform/api/serializers.py
# ... (其他导入和 Serializer) ...class TestCaseSerializer(serializers.ModelSerializer):# ... (原有字段定义) ...class Meta:model = TestCasefields = ['id', 'name', 'description', 'module', 'module_name', 'project_id', 'project_name','priority', 'priority_display','request_method', 'request_url', 'request_headers', 'request_body', 'assertions', 'extract_params',  # 新增字段'precondition', 'steps_text', 'expected_result','case_type', 'case_type_display', 'maintainer','create_time', 'update_time']# ... (extra_kwargs 保持不变) ...

第二部分:后端测试执行器强化

改造测试执行器,使其支持参数提取和注入。

1. 修改 execute_api_test_case 函数

打开 test-platform/api/services/test_executor.py进行修改。

# test-platform/api/services/test_executor.py
import requests
import json
import time
import urllib.parse
import re
from typing import Dict, List, Any, Tuple, Optional
from ..models import TestCase, Environment# --- 断言类型 ---
ASSERTION_TYPE_STATUS_CODE = "status_code"
ASSERTION_TYPE_BODY_CONTAINS = "body_contains"
ASSERTION_TYPE_JSON_PATH_EQUALS = "json_path_equals"
ASSERTION_TYPE_HEADER_EQUALS = "header_equals"try:from jsonpath_ng import jsonpath, parse as jsonpath_parse
except ImportError:jsonpath_parse = None  # type: ignoreprint("WARNING: jsonpath_ng not installed. JSONPath assertions will not work.")def execute_api_test_case(test_case: TestCase, environment: Optional[Environment] = None,context_variables: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:"""执行单个 API 测试用例并返回结果字典。可以传入 environment 对象,用于动态替换 base_url 和添加公共请求头。context_variables: 上下文变量字典,用于参数注入和提取"""# 初始化上下文变量字典(如果未提供)if context_variables is None:context_variables = {}result = {"status": "ERROR",  # 默认是错误状态"request_data": {},"response_data": {},"assertion_results": [],"error_message": None,"duration": 0.0,"context_variables": context_variables  # 返回更新后的上下文变量}start_time = time.time()try:# 1. 解析请求参数并应用环境配置method = test_case.request_method.upper()original_url = test_case.request_urlfinal_url = original_url # 最终发送请求的 URL# 如果提供了环境,应用其 base_url 和 config_dataenvironment_headers = {}environment_config_data = {}if environment:if environment.base_url and original_url and not original_url.startswith(('http://', 'https://')):# 如果 test_case.request_url 是相对路径,则拼接 base_urlfinal_url = f"{environment.base_url.rstrip('/')}/{original_url.lstrip('/')}"elif not original_url: # 如果用例没有填写 URL,并且有环境,则使用环境的 base_urlfinal_url = environment.base_url# 解析环境的 config_dataif environment.config_data:try:environment_config_data = environment.config_data# 例如,从 config_data 中获取 headersenvironment_headers = environment_config_data.get('headers', {})except Exception as e:result["error_message"] = f"环境配置数据解析失败: {e}"return result# 验证URL格式parsed_url = urllib.parse.urlparse(final_url)if not parsed_url.scheme:final_url = f"https://{final_url}"  # 默认使用https# 2. 参数注入 - 替换URL中的变量占位符try:final_url = replace_variables(final_url, context_variables)except Exception as e:result["error_message"] = f"URL参数注入失败: {str(e)}"result["duration"] = time.time() - start_timereturn resultheaders = {}if test_case.request_headers:try:headers = json.loads(test_case.request_headers)# 参数注入 - 替换请求头中的变量占位符headers = replace_variables_in_dict(headers, context_variables)except json.JSONDecodeError:result["error_message"] = "请求头 JSON 格式错误"result["duration"] = time.time() - start_timereturn resultexcept Exception as e:result["error_message"] = f"请求头参数注入失败: {str(e)}"result["duration"] = time.time() - start_timereturn result# 合并环境的通用请求头和用例自定义的请求头# 用例自定义的头可以覆盖环境的头final_headers = {**environment_headers, **headers}body = test_case.request_body# 参数注入 - 替换请求体中的变量占位符if body:try:# 检查是否是JSON格式的请求体if final_headers.get('Content-Type', '').lower().startswith('application/json'):try:body_dict = json.loads(body)body_dict = replace_variables_in_dict(body_dict, context_variables)body = json.dumps(body_dict)except json.JSONDecodeError:# 如果不是有效的JSON,则作为字符串处理body = replace_variables(body, context_variables)else:# 非JSON格式,直接替换字符串body = replace_variables(body, context_variables)except Exception as e:result["error_message"] = f"请求体参数注入失败: {str(e)}"result["duration"] = time.time() - start_timereturn resultresult["request_data"] = {"method": method,"url": final_url,"headers": final_headers,"body": body,}# 3. 发送 HTTP 请求response = Noneif method == 'GET':response = requests.get(final_url, headers=final_headers, timeout=10)elif method == 'POST':if final_headers.get

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/88093.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/88093.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/88093.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PCA通过“找最大方差方向”实现降维,本质是用更少的变量捕捉原始数据的主要模式

什么事 PCA(主成分分析) PCA(主成分分析)的原理与通俗举例 PCA 是什么? PCA(Principal Component Analysis)是一种常用的降维算法,核心目标是将高维数据映射到低维空间,同时尽可能保留原始数据的关键信息(方差最大的方向)。 核心原理:找“最能代表数据的方向”…

JAVA synchronized关键字涉及的Monitor对象中 EntryList和WaitSet工作机制

在Java的synchronized同步机制中,Monitor对象的EntryList和WaitSet是两个关键队列,它们分别管理不同状态的线程。下面我将详细解释它们的工作原理,并提供代码示例说明。 EntryList(锁竞争队列) 作用机制 EntryList保…

js-day10

JS学习之旅-day101. 作用域1.1 局部作用域1.2 全局作用域1.3 作用域链1.4 JS垃圾回收机制(GC)1.5 闭包1.6 变量提升2. 函数进阶2.1 函数提升2.2 函数参数2.3 箭头函数3. 解构赋值3.1 数组解构3.2 对象解构4. 数组遍历4.1 forEach4.2 filter1. 作用域 作…

智能数字式毫秒计在实际生活场景中的应用

在电力领域,SYN5307型数字毫秒表可精准监测特高压变电站断路器合闸时间差,定位继电保护装置信号延迟;工业自动化中,优化汽车焊装线时序、提升半导体晶圆切割良率;科研计量上,助力量子通信同步校准&#xff…

Java面试基础:概念

1. Java的特点跨平台性:Java的 “编写一次,运行无处不在” 是其最大的特点之一。Java编译器将源代码编译成字节码(bytecode),该字节码可以在任何安装了Java虚拟机(JVM)的系统上运行。面向对象:Java是一门严格的面向对象编程语言&a…

PyQt5高级窗口控件详解:停靠窗口、多文档界面与滚动条

掌握PyQt5的高级窗口控件,让你的GUI应用具备专业级的布局与交互体验 在PyQt5应用开发中,高效管理窗口布局和实现复杂交互功能是提升用户体验的关键。本文将深入解析三个核心高级控件:停靠窗口(QDockWidget)、多文档界面…

50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | DrawingApp(画板组件)

&#x1f4c5; 我们继续 50 个小项目挑战&#xff01;—— DrawingApp组件 仓库地址&#xff1a;https://github.com/SunACong/50-vue-projects 项目预览地址&#xff1a;https://50-vue-projects.vercel.app/ 使用 Vue 3 的 Composition API&#xff08;<script setup>…

Eureka、Nacos、LoadBalance、OpenFeign​之间的区别联系和协作 (附代码讲解)

这篇文章聊聊微服务里的这几个老伙计&#xff1a;Eureka、Nacos、LoadBalance、OpenFeign。咱们做微服务开发&#xff0c;总会跟这几个组件打交道&#xff1a;Eureka、Nacos、Spring Cloud LoadBalancer、OpenFeign。它们各司其职又互相配合&#xff0c;今天就把它们的关系、用…

JavaSE-继承

继承&#xff08;inheritance&#xff09;继承的意义我们首先来看下面两个类&#xff1a;public class Dog {public String name;public int age;public void eat(){System.out.println(this.name"正在吃饭");}public void bark(){System.out.println(this.name"…

第二届虚拟现实、图像和信号处理国际学术会议(VRISP 2025)

重要信息 官网&#xff1a;www.icvisp.net 时间&#xff1a;2025年8月1-3日 地点&#xff1a;中国-长沙 简介 近年来&#xff0c;虚拟现实技术取得了显著进步&#xff0c;与5G、云计算和物联网等新一代信息技术的融合加速&#xff0c;推动了其在硬件、软件和内容应用等方面…

SpringBoot+Mybatis+MySQL+Vue+ElementUI前后端分离版:整体布局、架构调整(二)

目录 一、前言 二、后端调整 1.实体类调整 2.菜单相关接口 3.用户相关接口 4.新增工具类 5.新增菜单树返回类 6.配置类、拦截器 三、前端调整 1.请求调整 2.页面布局、样式调整 1.user.vue 2.index.vue 3.请求拦截 四、开发过程中的问题 五、附&#xff1a…

vue3官方文档学习心得

这几天抽空把vue3的文档整个看了一遍。简介 | Vue.js 23年写过一个vue2的项目&#xff0c;24年写了一个vue3的项目&#xff0c;页面功能比较简单&#xff0c;用几个简单的API&#xff0c;watch、watchEffect、ref、reactive就能实现的业务功能。 写了几年的react的&#xff0…

Pycharm恢复默认设置,配置导致复制粘贴等不能使用

在file 种找到manage IDE settings在manage IDE settings中找到restore default settings

【王树森推荐系统】召回12:曝光过滤 Bloom Filter

概述 曝光过滤通常是在召回阶段做&#xff0c;具体的方法就是用 Bloom Filter 曝光过滤问题 如果用户看过某个物品&#xff0c;则不再把该物品曝光给用户。原因是同一个物品重复曝光给用户会损害用户体验&#xff0c;但也不是所有推荐系统都有曝光过滤&#xff0c;像 youtube 这…

基于STM32单片机的心率血氧监测系统设计(STM32代码编写+手机APP设计+PCB设计+Proteus仿真)

系列文章目录 文章目录 系列文章目录前言1 资料获取与演示视频1.1 资料介绍1.2 资料获取1.3 演示视频 2 系统框架3 硬件3.1 主控制器3.2 显示屏3.3 WIFI模块3.4心率血氧传感器 4 设计PCB4.1 安装下载立创EDA专业版4.2 画原理图4.4 使用嘉立创下单助手进行下单&#xff0c;打板。…

main(int argc,char **agrv)的含义

今天和大家讨论一个常见的但是不容易深入了解的知识点。那就是 main 函数声明中使用到的 argc 和 argv 的含义。通常我们写主函数的时候一般都是直接使用int main() 或者 void main() 来声明 main 函数。但是你知道吗&#xff1f;在c89/c99的语言标准中&#xff0c;main函数的声…

如何简单实现发版不影响客户使用?nginx负载

nginx负载发版不影响客户使用 1.需要二台服务器 2.二台服务器均是正式环境配置 3.服务器Nginx配置修改 发版顺序&#xff1a;先在服务器2发版&#xff0c;发布成功后&#xff0c;再改服务器Nginx配置&#xff0c;重新加载nginx&#xff1b;然后在服务器再发版&#xff0c;发布成…

qt笔记(1)——Qtablewidget使用

1.基础使用方法 &#xff08;略&#xff09; 2.坑和注意点 2.1 设置一个单元格的编辑属性 在代码中&#xff0c;想要修改一个单元格的编辑属性&#xff0c;需要对这个item的flags进行设置&#xff1b;注意对一个tablewidget的一个item成员进行设置后&#xff0c;进行一次编…

字符串的模糊匹配方法介绍

字符串的模糊匹配方法介绍 目录字符串的模糊匹配方法介绍一、编辑距离&#xff08;Levenshtein Distance&#xff09;复杂度分析二、Jaro-Winkler 距离复杂度分析三、最长公共子序列&#xff08;LCS&#xff09;复杂度分析四、模糊搜索&#xff08;Fuzzy Search&#xff09;复杂…

ActiveMQ在Spring Boot中的详细使用指南

📋 目录 🚀 ActiveMQ简介 什么是ActiveMQ? 核心概念 🏗️ 基础架构组件 📝 重要概念解释 ActiveMQ vs 其他消息中间件 🔧 环境搭建 1. ActiveMQ服务端安装 Docker方式(推荐初学者) 手动安装方式 2. 验证安装 访问Web管理界面 连接参数 测试连接 �…