背景:需要对多个不同条件进行动态断言的场景,比如接口自动化测试中,可以灵活地根据不同的业务需求调整断言条件,而无需修改核心逻辑,如多个getdata接口的通用动态断言,需要根据不同条件进行断言

1、原始代码

// 动态断言-getdata接口通用处理
function dynamicAssertAndSetEnv(data, conditions) {
    for (const { name, key, condition, envKey } of conditions) {
        if (data.hasOwnProperty(key.split('.')[0])) {
            const value = key.split('.').reduce((obj, prop) => obj && obj[prop], data); // 获取嵌套字段值
            if (value !== undefined && value !== null) {
                pm.test(`${name} 不为空/0值`, () => {
                    pm.expect(value).to.satisfy(condition);
                });
                if (envKey) {
                    pm.environment.set(envKey, value); // 设置环境变量
                    console.log(`环境变量 ${envKey} 为 ${value}`);
                }
                // 如果是内容提取卡片的 finish_count,则额外提取 survey_id
                if (name === "内容提取卡片的 finish_count" && data.data.survey_id !== undefined) {
                    pm.environment.set("survey_id", data.data.survey_id); // 设置问卷变量 ID
                    console.log(`环境变量 survey_id 为 ${data.data.survey_id}`);
                }
                return true; // 如果某个条件满足,则停止后续判断
            }
        }
    }
    return false; // 如果所有条件都不满足,则返回 false
}

// 添加断言逻辑(通用版)
function assertOutputStatus(firstDataItem,statusCode) {
    pm.test("output_status 返回 20", () => {
        pm.expect(statusCode).to.equal(20);
    });

    // 定义动态断言条件及环境变量设置规则
    const conditions = [
        { name: "数据抓取卡片的 count", key: "data.count", condition: (val) => val > 0, envKey: "count" },
        { name: "数据清洗卡片的 count", key: "data.clean_data.count", condition: (val) => val > 0, envKey: "count" },
        { name: "图片解析卡片的 success_count", key: "data.success_count", condition: (val) => val > 0, envKey: "success_count" },
        { name: "内容提取卡片的 finish_count", key: "data.finish_count", condition: (val) => val > 0, envKey: "finish_count" },
        { name: "数据处理卡片的 user_count", key: "data.user_count", condition: (val) => val > 0, envKey: "user_count" }
    ];

    // 动态生成断言并设置环境变量
    if (!dynamicAssertAndSetEnv(firstDataItem, conditions)) {
        console.warn("未找到符合条件的字段,跳过断言和环境变量设置");
    }
}


data: 这是一个对象,代表从接口获取的数据。这个数据结构可以非常复杂,包含多层嵌套的对象或数组,我这里代表firstDataItem

conditions:为数组,其中每个元素是一个对象,定义了需要检查的条件

1、使用了 for...of 循环来遍历 conditions 数组,并在满足条件时立即返回 true

2、通过 data.hasOwnProperty(key.split('.')[0]) 检查 data 对象是否包含指定的顶级属性,对每个条件逐一检查,直到遍历完所有条件或执行某些逻辑后退出

优点:

直观易懂,对于熟悉传统循环结构的开发者来说,这种写法非常直观,易于理解和维护

有明确的控制流,可以显式地控制循环的终止条件(例如通过 break 或 return),适合需要复杂逻辑处理的情况

缺点:

存在性能问题即使在找到满足条件的第一个元素后,仍然会继续迭代剩余的元素,除非显式中断循环且代码显得较为冗长

2、优化后的代码

// 动态断言-getdata接口通用处理
const dynamicAssertAndSetEnv = (data, conditions) => {
    return conditions.some(({ name, key, condition, envKey }) => {
        const value = key.split('.').reduce((obj, prop) => obj && obj[prop], data);
        
        // 检查是否满足条件
        if (value !== undefined && value !== null && condition(value)) {
            pm.test(`${name} 不为空/0值`, () => pm.expect(value).to.satisfy(condition));
            
            // 设置环境变量
            if (envKey) pm.environment.set(envKey, value);
            console.log(`环境变量 ${envKey} 为 ${value}`);

            // 特殊处理:如果名称是 "内容提取卡片的 finish_count",则额外提取 survey_id
            if (name === "内容提取卡片的 finish_count" && data.data?.survey_id !== undefined) {
                pm.environment.set("survey_id", data.data.survey_id);
                console.log(`环境变量 survey_id 已设置为 ${data.data.survey_id}`);
            }

            return true; // 条件满足,停止后续判断
        }
        return false; // 条件不满足,继续检查下一个条件
    });
};


// 添加断言逻辑(通用版)
function assertOutputStatus(firstDataItem,statusCode) {
    pm.test("output_status 返回 20", () => {
        pm.expect(statusCode).to.equal(20);
    });

    // 定义动态断言条件及环境变量设置规则
    const conditions = [
        { name: "数据抓取卡片的 count", key: "data.count", condition: (val) => val > 0, envKey: "count" },
        { name: "数据清洗卡片的 count", key: "data.clean_data.count", condition: (val) => val > 0, envKey: "count" },
        { name: "图片解析卡片的 success_count", key: "data.success_count", condition: (val) => val > 0, envKey: "success_count" },
        { name: "内容提取卡片的 finish_count", key: "data.finish_count", condition: (val) => val > 0, envKey: "finish_count" },
        { name: "数据处理卡片的 user_count", key: "data.user_count", condition: (val) => val > 0, envKey: "user_count" }
    ];

    // 动态生成断言并设置环境变量
    if (!dynamicAssertAndSetEnv(firstDataItem, conditions)) {
        console.warn("未找到符合条件的字段,跳过断言和环境变量设置");
    }
}

1、利用 some 方法来遍历数组,一旦找到符合条件的元素即停止进一步迭代,避免了不必要的额外操作

2、这里使用了解构赋值语法直接从 conditions 数组的每个对象中解构并提取出 namekeycondition, 和 envKey 属性,简化了访问这些属性的方式

优点

采用了现代 JavaScript 的特性,符合当前开发趋势,有助于提高团队代码的一致性和可维护性

通过使用箭头函数和解构赋值,代码更加紧凑且易于阅读

缺点:对于不熟悉 ES6+ 特性的开发者来说,可能需要额外的学习成本来理解 some 方法和箭头函数等新特性

总结:核心功能是从复杂的 data 对象中提取指定路径下的值,并对该值进行条件检查。如果条件满足,则执行相应的操作(例如断言和设置环境变量)。在这里,优化后的代码,是通过使用 some 方法和解构赋值,代码能够高效地遍历条件列表并在找到第一个满足条件的项后立即停止,从而提高了性能并简化了逻辑

3、以上方法是用了遍历方法,适用需要遍历的场景,处理效率将大打折扣,如果能根据指定条件匹配,不妨我们换另一种思路,场景如下:

根据不同的 relation_type 来区分组件,并进行断言和环境变量设置,摒弃了遍历的粗暴写法

// 动态断言和环境变量设置
    function dynamicAssertAndSetEnv(firstDataItem, relationType) {
    const conditionsMap = {
        "22,27,26,28": { name: "文章/电商/视频抓取总数", key: "data.count", condition: (val) => val > 0, envKey: "count" },
        23: { name: "数据清洗保留总数", key: "data.clean_data.count", condition: (val) => val > 0, envKey: "count" },
        "24,6": { name: "图片/视频解析成功数", key: "data.success_count", condition: (val) => val > 0, envKey: "success_count" },
        "16,17,46": { name: "内容提取/文本总结/评分工具成功数", key: "data.finish_count", condition: (val) => val > 0, envKey: "finish_count" },
        7: { name: "数据源处理成功数", key: "data.user_count", condition: (val) => val > 0, envKey: "user_count" },
        10: { name: "报告生成成功数", key: "data.unit_count", condition: (val) => val > 0, envKey: "unit_count" }
    };

    const condition = Object.entries(conditionsMap).find(([key]) => key.split(",").includes(String(relationType)))?.[1];
    if (!condition) {
        console.error(`无匹配条件 relation_type=${relationType},失败!!!`);
        return false;
    }

    // 获取嵌套字段值并断言
    const value = getFieldByPath(firstDataItem, condition.key);
    if (value !== undefined && value !== null) {
        pm.test(`${condition.name} 大于0`, () => {
            pm.expect(value).to.satisfy(condition.condition, `条件不满足:${condition.name} 的值为 ${value}`);
        });

        if (condition.condition(value)) {
            if (condition.envKey) {
                pm.environment.set(condition.envKey, value);
                console.log(`环境变量 ${condition.envKey}: ${value}`);
            }

            // 特殊处理逻辑;内容提取和数据报告、数据处理
            handleSpecialCases(firstDataItem, relationType);
           
            console.log(`断言并提取变量成功`);
            return true; 
            
        } else {
            console.error(`条件不满足:${condition.name} 的值为 ${value}`);
            return false;
        }
    } else {
        console.error(`字段为null/undefined:${condition.key}`);
        return false;
    }
}

// 获取嵌套字段值
function getFieldByPath(obj, path) {
    return path.split('.').reduce((o, prop) => o && o[prop], obj);
}

 // 特殊处理逻辑
function handleSpecialCases(firstDataItem, relationType) {
    if ([16, 10].includes(relationType) && firstDataItem.data.survey_id !== undefined) {
        pm.environment.set("survey_id", firstDataItem.data.survey_id);
        console.log(`环境变量 survey_id: ${firstDataItem.data.survey_id}`);
    } 
    
    if (relationType === 7 && firstDataItem.data.resource_id !== undefined) {
        pm.environment.set("datasource_id", firstDataItem.data.resource_id);
        console.log(`环境变量 datasource_id: ${firstDataItem.data.resource_id}`);
    }
}
// 添加断言逻辑
function assertOutputStatus(firstDataItem, relationType) {
    const result = dynamicAssertAndSetEnv(firstDataItem, relationType);
    if (!result) {
        console.warn("无匹配条件或条件不满足,跳过环境变量设置");
    }
}

// 轮询结束后调用断言
 assertOutputStatus(firstDataItem,  relationType); 
          

更多推荐