You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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) ?: [];
    }
}

三、使用步骤

  1. 录入API元数据:在api_definitions表中添加15个API的所有配置,包括模板、规则和必填字段,一次录入永久复用。
  2. 创建工作流:在test_workflows表中定义测试流程的API执行顺序(比如50步的混合流程)。
  3. 设置测试变量:在test_case_vars表中为每个工作流的每个API配置变量值,不同测试场景只需要修改变量,不用改工作流或API模板。
  4. 执行工作流:实例化WorkflowRunner并调用run方法,传入工作流ID,即可自动执行整个流程,得到每个步骤的执行结果。

四、优化方向

  • 做一个简单的Web管理界面(PHP+HTML),不用直接操作数据库就能管理API、工作流和变量。
  • 新增测试日志表,记录每次工作流的执行时间、每个API的请求和响应,方便排查问题。
  • 支持跨API变量传递:比如把前一个API的响应字段作为后一个API的变量,可在workflow_rules中定义映射规则,执行时自动提取值存入变量池。

内容的提问来源于stack exchange,提问作者pengwin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 10:42:33