一、嵌入式工程师,为什么对 AI 最谨慎
在软件行业里,嵌入式工程师对 AI 的态度大概是最出了名的谨慎。
不是落后,恰恰是专业。一行 C 代码要跑在真实设备上、要进认证材料,测试结果讲不清来源,认证方第一个不答应;错误要拿认证周期和产品安全去换。所以他们不是拒绝 AI,而是不接受一个不可控的 AI——最消耗人力的单元测试,很多团队至今仍是工程师一条一条手写。
但最近 Parasoft 官方公众号发布的一个案例,让这份谨慎出现了松动——台湾兆普动力科技,一家动力能源软硬件研发企业,把 AI 智能体直接用进了 C/C++ 单元测试流程。
值得看的不是"又一家用了 AI",而是他们怎么让 AI 的测试结果可解释、可留痕、可支撑认证交付。
二、先上一段代码:嵌入式单元测试到底难在哪
说明:下面是一段典型的动力电池放电保护逻辑,示例代码,用来还原嵌入式单元测试的真实处境。
/* battery_guard.c —— 动力电池放电保护(示例) */
#include "battery_guard.h"
#define TEMP_HIGH_C 60 /* 温度上限(℃) */
#define TEMP_LOW_C –20 /* 温度下限(℃) */
#define SOC_CRITICAL 15 /* 电量保护阈值(%) */
#define VOLT_MIN_MV 2900 /* 电压下限(mV) */
BmsStatus battery_discharge_guard(const BatteryState *state)
{
if (state == NULL) {
return BMS_ERR_PARAM;
}
/* 温度越界:优先级最高,直接切主继电器 */
if (state->temp_c > TEMP_HIGH_C || state->temp_c < TEMP_LOW_C) {
relay_open(RELAY_MAIN);
logger_emit(LOG_ALERT, "temp out of range: %d", state->temp_c);
return BMS_CUTOFF_TEMP;
}
/* 低电量且电压跌破下限:进入保护 */
if (state->soc_pct < SOC_CRITICAL && state->volt_mv < VOLT_MIN_MV) {
relay_open(RELAY_MAIN);
return BMS_CUTOFF_SOC;
}
return BMS_OK;
}
不到 30 行的保护函数,测试同学看到的是三座大山:
三、手工时代:桩自己写,用例自己排
先看打桩。为了让被测函数独立执行,你得把硬件动作"截获":
/* 手写桩:截获继电器动作,记录调用情况 */
static int relay_open_cnt = 0;
static RelayId last_relay = RELAY_NONE;
void relay_open(RelayId id)
{
relay_open_cnt++;
last_relay = id; /* 真实硬件动作被"截获",测试环境里安全 */
}
void setUp(void)
{
relay_open_cnt = 0; /* 桩的计数器不清零,跨用例断言就会串台 */
last_relay = RELAY_NONE;
}
再看用例。光是第二个判定 soc_pct < 15 && volt_mv < 2900,MC/DC 就要求至少 4 组用例做独立翻转:
| T1 | 14 | 2800 | BMS_CUTOFF_SOC | 两条件同时为真 |
| T2 | 14 | 2900 | BMS_OK | 单独翻转"电压"条件 |
| T3 | 20 | 2800 | BMS_OK | 单独翻转"电量"条件 |
| T4 | 20 | 2900 | BMS_OK | 基线(两条件均假) |
/* 手写用例示例:T1 —— 低电量 + 低电压,切保护 */
void test_low_soc_and_low_volt_cutoff(void)
{
BatteryState s = { .temp_c = 25, .soc_pct = 14, .volt_mv = 2800 };
BmsStatus st = battery_discharge_guard(&s);
TEST_ASSERT_EQUAL(BMS_CUTOFF_SOC, st);
TEST_ASSERT_EQUAL_INT(1, relay_open_cnt); /* 继电器确实被拉开 */
}
注意 T2 这组参数:volt_mv = 2900 恰好不触发——因为判定是严格小于。这种"差 1 就不一样"的细节,手工排用例时最容易漏。
而这只是一个函数里的一个判定。真实的 BMS 模块动辄几百个函数、上千个判定、几十个外部依赖——用例设计、桩函数编写、场景配置、覆盖率补测,全部压在工程师手上。这正是官方案例里兆普动力科技的处境:测试用例依赖人工设计、桩函数准备成本高、覆盖率永远差最后几步、认证周期被测试拖着走。
四、方案拆解:算法打底,AI 只做增量
Parasoft 给出的方案是双层结构——这也是它区别于"AI 一把梭"的地方。
第一层,C/C++test 原生算法先打底。 工具原有单元测试算法先分析被测函数、接口与数据关系,生成可执行的基础用例并完成首轮验证。这一层不依赖 AI,稳定、可复现,是整条测试链的地基。
第二层,AI 智能体做增量。 在基础测试集之上,AI 自动补充测试场景、针对外部函数和底层接口自动生成并配置桩函数——工程师不用从零准备,精力留给关键场景确认和异常结果评审。
然后是闭环:
基础算法用例(确定性打底)
│
▼
┌──► 执行 ──► 覆盖率 / 失败分析 ──► AI 生成补充用例 + 桩配置 ──┐
│ │
└────────────────────◄───────────────────────────────────────┘
直到覆盖率缺口收敛
每一轮执行后,AI 根据未覆盖代码与判定路径继续生成补充用例。落到上面那段代码,AI 补测瞄准的正是人工最容易漏的部分(以下为示意代码,用来说明补测的目标形态,非案例原始产物):
/* AI 智能体补充用例(示意):瞄准边界值、独立翻转路径与异常入口 */
void test_ai_supplemented_boundaries(void)
{
BatteryState s = { .temp_c = 25 };
/* 边界对:恰好 2900mV 不触发(严格小于),2899mV 触发 */
s.soc_pct = 14;
s.volt_mv = 2900; TEST_ASSERT_EQUAL(BMS_OK, battery_discharge_guard(&s));
s.volt_mv = 2899; TEST_ASSERT_EQUAL(BMS_CUTOFF_SOC, battery_discharge_guard(&s));
/* 温度边界:恰好 +60℃ 不触发,+61℃ 触发切温控保护 */
s.soc_pct = 80; s.volt_mv = 3600;
s.temp_c = 60; TEST_ASSERT_EQUAL(BMS_OK, battery_discharge_guard(&s));
s.temp_c = 61; TEST_ASSERT_EQUAL(BMS_CUTOFF_TEMP, battery_discharge_guard(&s));
/* 异常路径:空指针入参 */
TEST_ASSERT_EQUAL(BMS_ERR_PARAM, battery_discharge_guard(NULL));
}
据 Parasoft 官方公众号案例分享,在当前客户适配场景中,该方案可实现行覆盖率 90% 以上、MC/DC 85% 以上。
这个数字里最有分量的是 MC/DC——做过安全关键软件的人都清楚,它是认证里最难啃的覆盖指标。
五、“AI 说了不算”,才是敢用的原因
回到开头的问题:对 AI 最谨慎的行业,凭什么先用了?
因为在这个方案里,AI 说了不算。基础用例由确定性算法生成,AI 只负责增量补测;工程师评审关键结果;每一步辅助工作都留痕,质量数据完整可度量。用官方的话说——“不是用 AI 替代测试工具,而是让 AI 在成熟测试引擎之上持续放大自动化能力”。
这正是安全关键行业接受 AI 的前提:不是 AI 有多快,而是失控的风险被锁住了。
落地也按工程节奏推进:从接入客户工程、建立基础测试,到 AI 自动生成与打桩、针对缺口持续补测,再到工程师评审、输出可复用测试资产;Parasoft 技术支持工程师全程参与环境适配,客户不用自己摸索集成。
总结
单元测试的困境从来不是"会不会做",而是投入产出比撑不起代码规模的增长。这个案例的解法,是把"人工逐条补测"升级为"工具算法 + AI 智能体协同驱动的工程能力":确定性算法保底,AI 只做增量,工程师守住评审关口。
评论区聊聊:你的项目单元测试覆盖率现在是什么水平?卡在哪一步——写用例、打桩,还是补覆盖?
这里是慧都小项,欢迎咨询沟通~

注:本文案例信息与数据引自 Parasoft 官方微信公众号《案例分享|台湾兆普动力科技 × Parasoft AI 智能体:嵌入式 C/C++ 测试迈入自主智能时代》,覆盖率数据均指官方披露的当前客户适配场景表现。文中代码为说明性示例,非案例原始产物。




