LAMP栈下多API聚合服务的E2E测试请求复用方案咨询
基于LAMP栈的可复用API工作流测试实现方案
核心思路是把15个API的元数据(请求模板、规则、必填字段)和工作流序列存在MariaDB,用PHP实现一个轻量工作流引擎,动态渲染请求、校验规则、执行整个测试流程,彻底告别Postman里复制粘贴的重复劳动。
一、数据库表设计(MariaDB)
先建三张表存储API配置、工作流序列和测试变量:
-- 存储每个API的元数据 CREATE TABLE api_definitions ( id INT AUTO_INCREMENT PRIMARY KEY, api_name VARCHAR(100) NOT NULL UNIQUE, aggregator_params JSON NOT NULL, -- 聚合器统一入口的调用标识,比如{"api_code": "USER_REG"} request_headers_template JSON NOT NULL, -- 带变量的请求头模板,示例: {"Authorization": "{{auth_token}}"} request_body_template JSON NOT NULL, -- 带变量的请求体模板,示例: {"user_id": "{{test_user_id}}"} required_fields JSON NOT NULL, -- 必填字段列表,示例: ["user_id", "auth_token"] workflow_rules JSON NOT NULL -- 工作流规则,示例: {"idempotency_key": "req_id", "predecessor_apis": [3], "order": 2} ); -- 存储工作流的API执行顺序 CREATE TABLE test_workflows ( id INT AUTO_INCREMENT PRIMARY KEY, workflow_name VARCHAR(100) NOT NULL, api_sequence JSON NOT NULL -- 示例: [1,3,5,2] 对应api_definitions的ID顺序 ); -- 存储每个工作流中各API的测试变量 CREATE TABLE test_case_vars ( id INT AUTO_INCREMENT PRIMARY KEY, workflow_id INT NOT NULL, api_id INT NOT NULL, variables JSON NOT NULL, -- 示例: {"auth_token": "xyz789", "test_user_id": "u_test_001"} FOREIGN KEY (workflow_id) REFERENCES test_workflows(id), FOREIGN KEY (api_id) REFERENCES api_definitions(id) );
二、PHP核心功能实现
1. 请求模板渲染与必填字段校验
写一个工具类,负责把带{{变量名}}的模板替换成实际值,同时检查必填字段是否齐全:
class TemplateHandler { // 渲染模板,替换变量 public static function render(array $template, array $vars): array { $output = []; foreach ($template as $key => $val) { if (is_string($val) && preg_match('/{{(.*?)}}/', $val, $matches)) { $varName = trim($matches[1]); if (!isset($vars[$varName])) { throw new Exception("变量 $varName 未定义"); } $output[$key] = $vars[$varName]; } else { $output[$key] = $val; } } return $output; } // 校验必填字段 public static function checkRequired(array $vars, array $requiredFields): void { foreach ($requiredFields as $field) { if (!isset($vars[$field])) { throw new Exception("必填字段 $field 缺失"); } } } }
2. 工作流规则校验器
处理幂等性、调用顺序这类规则,确保流程符合要求:
class RuleChecker { private $executedApis = []; private $idempotencyRecords = []; // 检查当前API是否按顺序执行 public function validateOrder(int $currentApiId, array $sequence): void { $currentPos = array_search($currentApiId, $sequence); if ($currentPos === false) { throw new Exception("API $currentApiId 不在当前工作流序列中"); } // 检查前置API是否都已执行 for ($i = 0; $i < $currentPos; $i++) { $preApi = $sequence[$i]; if (!in_array($preApi, $this->executedApis)) { throw new Exception("必须先执行API $preApi,才能执行当前API"); } } } // 校验幂等性,避免重复提交 public function validateIdempotency(int $apiId, array $rules, array $vars): void { if (isset($rules['idempotency_key'])) { $keyName = $rules['idempotency_key']; if (!isset($vars[$keyName])) { throw new Exception("幂等键 $keyName 缺失"); } $keyVal = $vars[$keyName]; if (isset($this->idempotencyRecords["$apiId:$keyVal"])) { throw new Exception("API $apiId 已使用幂等键 $keyVal 执行过"); } $this->idempotencyRecords["$apiId:$keyVal"] = true; } } // 标记API已执行 public function markExecuted(int $apiId): void { $this->executedApis[] = $apiId; } }
3. 工作流执行器
读取数据库中的配置,依次执行每个API,调用聚合器入口并返回结果:
class WorkflowRunner { private $dbConn; public function __construct(mysqli $db) { $this->dbConn = $db; } public function run(int $workflowId): array { $results = []; // 获取工作流信息 $stmt = $this->dbConn->prepare("SELECT workflow_name, api_sequence FROM test_workflows WHERE id = ?"); $stmt->bind_param("i", $workflowId); $stmt->execute(); $workflow = $stmt->get_result()->fetch_assoc(); $apiSequence = json_decode($workflow['api_sequence'], true); $ruleChecker = new RuleChecker(); foreach ($apiSequence as $apiId) { // 获取API定义 $stmt = $this->dbConn->prepare("SELECT * FROM api_definitions WHERE id = ?"); $stmt->bind_param("i", $apiId); $stmt->execute(); $apiDef = $stmt->get_result()->fetch_assoc(); $requiredFields = json_decode($apiDef['required_fields'], true); $workflowRules = json_decode($apiDef['workflow_rules'], true); // 获取当前API的测试变量 $stmt = $this->dbConn->prepare("SELECT variables FROM test_case_vars WHERE workflow_id = ? AND api_id = ?"); $stmt->bind_param("ii", $workflowId, $apiId); $stmt->execute(); $vars = json_decode($stmt->get_result()->fetch_assoc()['variables'], true); try { // 执行规则校验 $ruleChecker->validateOrder($apiId, $apiSequence); $ruleChecker->validateIdempotency($apiId, $workflowRules, $vars); TemplateHandler::checkRequired($vars, $requiredFields); // 渲染请求头和请求体 $renderedHeaders = TemplateHandler::render(json_decode($apiDef['request_headers_template'], true), $vars); $renderedBody = TemplateHandler::render(json_decode($apiDef['request_body_template'], true), $vars); // 调用聚合器统一入口 $aggregatorParams = json_decode($apiDef['aggregator_params'], true); $response = $this->callAggregator($aggregatorParams, $renderedHeaders, $renderedBody); // 标记API已执行 $ruleChecker->markExecuted($apiId); $results[] = [ 'api_id' => $apiId, 'api_name' => $apiDef['api_name'], 'status' => 'success', 'response' => $response ]; } catch (Exception $e) { $results[] = [ 'api_id' => $apiId, 'api_name' => $apiDef['api_name'], 'status' => 'failed', 'error_msg' => $e->getMessage() ]; // 可根据需求选择中断工作流或继续执行 break; } } return $results; } // 封装聚合器调用逻辑 private function callAggregator(array $params, array $headers, array $body): array { $ch = curl_init(); $url = "https://your-aggregator-domain.com/entry?" . http_build_query($params); // 格式化请求头 $formattedHeaders = []; foreach ($headers as $k => $v) { $formattedHeaders[] = "$k: $v"; } curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HTTPHEADER, $formattedHeaders); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); curl_close($ch); return json_decode($response, true) ?: []; } }
三、使用步骤
- 录入API元数据:在
api_definitions表中添加15个API的所有配置,包括模板、规则和必填字段,一次录入永久复用。 - 创建工作流:在
test_workflows表中定义测试流程的API执行顺序(比如50步的混合流程)。 - 设置测试变量:在
test_case_vars表中为每个工作流的每个API配置变量值,不同测试场景只需要修改变量,不用改工作流或API模板。 - 执行工作流:实例化
WorkflowRunner并调用run方法,传入工作流ID,即可自动执行整个流程,得到每个步骤的执行结果。
四、优化方向
- 做一个简单的Web管理界面(PHP+HTML),不用直接操作数据库就能管理API、工作流和变量。
- 新增测试日志表,记录每次工作流的执行时间、每个API的请求和响应,方便排查问题。
- 支持跨API变量传递:比如把前一个API的响应字段作为后一个API的变量,可在
workflow_rules中定义映射规则,执行时自动提取值存入变量池。
内容的提问来源于stack exchange,提问作者pengwin
相关产品推荐
相关产品推荐

