ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

TESSY嵌入式单元测试:C代码接口建模与安全认证实践

TESSY嵌入式单元测试:C代码接口建模与安全认证实践 1. TESSY不是“点点点就能跑”的测试工具而是嵌入式安全关键系统里的手术刀很多人第一次听说TESSY是在汽车电子、医疗设备或工业控制器的开发例会上——项目经理拍着桌子说“ISO 26262要求所有ASIL-B以上模块必须通过工具链认证的单元测试”然后有人递上一页印着“TESSY 4.5 Certified for ISO 26262 ASIL D”的PDF。那一刻TESSY在多数工程师心里就自动贴上了“高门槛”“流程重”“只给功能安全背书”的标签。但真实情况是TESSY最常被低估的价值恰恰在于它把“写测试用例”这件事从纯手工编码拉回到了工程化建模层面。它不让你写assert_equal(expected, actual)而是让你拖拽一个“输入信号发生器”连到“被测函数入口”再把“期望输出值表”拖进“验证节点”——整个过程像搭电路板而不是敲Python脚本。这背后有硬逻辑TESSY原生基于C/C源码解析非插桩式能直接读取.h头文件中的函数声明、结构体定义、宏定义甚至#ifdef条件编译分支它生成的测试驱动代码Test Harness完全符合MISRA-C:2012规则且自动生成的测试报告可直接导入DOORS或Polarion做需求追溯。换句话说你不是在“写测试”而是在用图形化界面完成对C代码接口契约的可视化建模。我曾帮一家BMS厂商重构测试流程他们原来用CppUTest手写300个测试用例平均每个用例要花2小时调试环境、处理头文件依赖、模拟CAN收发中断——改用TESSY后同样覆盖率下单个用例建模时间压到15分钟以内且所有测试用例自动继承项目级编译配置包括-DDEBUG1 -I./inc -I../mcu_driver再也不用担心“本地能跑CI服务器报错找不到头文件”。关键词里没填内容但热搜词已经暴露了真实战场vue单元测试报错和vectorcast 单元测试的并列出现恰恰说明开发者正在横向对比不同测试工具的适用边界。Vue前端测试失败往往卡在异步渲染时序或mock对象作用域VectorCAST强在航空电子领域的DO-178C认证支持但对AUTOSAR BSW模块的MCAL层驱动测试支持较弱而TESSY的不可替代性就藏在它对嵌入式C代码的零侵入式接口建模能力里——它不要求你改一行业务代码也不强制你引入任何测试框架头文件只要.c和.h文件存在它就能生成可编译、可调试、可覆盖分析的完整测试工程。所以如果你正面对的是一个已有十年历史的ECU控制算法模块里面混着浮点运算、查表法、状态机跳转还夹杂着#pragma pack(1)内存对齐指令……别急着翻CppUTest文档先打开TESSY把control_logic.c拖进去看它如何自动识别出void calc_torque(int16_t rpm, uint8_t gear, float32_t* output)这个函数的三个输入参数类型、一个指针输出以及output指向的内存是否在栈上分配——这才是TESSY创建测试工程的第一课它首先是一个C语言语义理解引擎其次才是测试执行平台。2. 创建工程前必须回答的三个“灵魂拷问”否则90%的失败源于此我见过太多团队在TESSY里折腾半天最后发现根本不是工具问题而是创建工程前没想清楚这三个问题。它们像三道安检门漏过任意一道后续所有操作都会变成“在流沙上盖楼”。2.1 你的被测代码SUT是否满足TESSY的“可测试性四原则”TESSY不是万能胶水它对被测代码有明确的静态结构要求。很多团队栽在第一步就是因为拿过来的代码违反了以下任一原则无全局副作用原则函数内部不能直接操作硬件寄存器如*(volatile uint32_t*)0x40023800 0x1也不能调用未声明的外部函数如裸写printf(debug)却没在头文件中声明。TESSY会报错Undefined symbol printf但它真正想告诉你的是“这个函数的边界不清晰无法隔离测试”。解决方案不是加#include stdio.h而是用接口抽象层——把printf封装成log_debug(const char* msg)并在测试工程中提供空实现stub。确定性输入输出原则函数不能依赖未传入的全局变量。比如int get_speed(void) { return g_current_speed; }TESSY无法为它生成有效测试用例因为g_current_speed的值在测试时不可控。正确做法是改为int get_speed(int current_speed)把隐式依赖显式化。TESSY的“输入信号发生器”只能驱动函数参数不能注入全局变量。无动态内存分配原则禁止在被测函数内使用malloc/free。TESSY生成的测试Harness运行在目标芯片的RAM中没有堆管理器。若必须测试动态分配逻辑需用内存池模拟预分配一块固定大小数组在测试时将其地址传入函数替代malloc返回值。无未定义行为原则比如对NULL指针解引用、数组越界访问、有符号整数溢出。TESSY的静态分析器Code Analysis会在工程创建阶段标红这些行但很多人忽略警告结果测试执行时直接触发HardFault。我的经验是把TESSY的静态分析警告级别调到最高Warning Level: All所有红色波浪线必须清零才能进入下一步。提示TESSY安装包自带TESSY_Tutorial项目其中Example_Calculation模块就是按这四原则编写的范本。建议新建工程前先用它跑通全流程再替换自己的代码——这是最快建立直觉的方式。2.2 你的编译环境是否已通过TESSY的“三重校验”TESSY不是独立编译器它需要调用你项目真实的交叉编译链如ARM GCC 9.3.1、Tasking C166等。但很多人以为“装了GCC就能用”结果卡在Compiler not found。真正的校验流程是路径校验TESSY的Tools → Options → Compiler中Compiler Path必须指向arm-none-eabi-gcc.exeWindows或arm-none-eabi-gccLinux的绝对路径且该路径不能含中文或空格。我曾遇到某客户因路径是D:\Program Files\GNU Tools ARM Embedded\9 2020-q2-update\bin\arm-none-eabi-gcc.exe空格导致TESSY静默失败。解决方案是创建软链接mklink /D D:\gcc9 D:\Program Files\GNU Tools ARM Embedded\9 2020-q2-update然后指向D:\gcc9\bin\arm-none-eabi-gcc.exe。版本校验TESSY 4.5官方支持GCC 7.x–9.x但实际测试发现GCC 9.3.1的-O2优化会生成TESSY无法解析的内联汇编。必须在Compiler Settings中添加-O1并禁用-finline-functions。这个细节官网文档没写是我在某次客户现场调试三天后发现的——当TESSY生成的Harness编译报错undefined reference to __aeabi_idiv时八成是优化级别过高触发了ARM软浮点库链接问题。头文件校验TESSY解析C代码时需要知道所有#include的搜索路径。这不同于编译器的-I参数TESSY要求你在Project → Properties → C/C General → Paths and Symbols中手动添加每一级头文件路径。常见错误是只加了./inc却漏了../mcu_driver/inc和../../rtos/cmsis/core_inc。TESSY不会报错但会导致函数参数类型识别错误如把uint32_t识别成int进而生成错误的测试驱动代码。2.3 你的测试目标究竟是“验证功能”还是“满足认证”这个问题决定整个工程的架构设计。如果目标是快速验证算法逻辑如PID控制器输出是否符合预期那么TESSY的“Quick Test”模式足够右键函数→Create Quick Test它自动生成最小化Harness你只需在表格里填几组输入/期望值。但如果目标是通过ASPICE或ISO 26262认证则必须启用Test Specification Mode测试规范模式在Project → New → Test Specification中创建.tsp文件而非直接建.tes测试用例每个测试用例必须关联需求ID如REQ_CTRL_001且需求文本需在TESSY内置需求管理器中维护测试用例必须包含Precondition前置条件如“电池电压12V”、Test Steps分步操作如“设置输入rpm3000”、Expected Result期望结果支持数值范围、字符串匹配、位掩码比对最终生成的测试报告.pdf或.xml会自动包含需求追溯矩阵RTM这是认证审核的必备材料。我服务过一家Tier1供应商他们最初用Quick Test模式做了200个用例审计时被否决——因为报告里没有需求ID关联无法证明“测试覆盖了所有需求”。返工时我们用Test Specification Mode重建工程虽然前期多花40小时配置需求管理器但后续每次新增需求只需在tsp文件里勾选对应用例RTM自动更新反而提升了长期效率。3. 从空白工程到可执行测试的六步实操链每一步都藏着“踩坑地图”创建TESSY测试工程不是点击“New Project”就完事。它是一条精密的流水线每一步的输出都是下一步的输入。下面是我梳理的、经过27个真实项目验证的六步链每步都标注了高频故障点和绕过方案。3.1 步骤一初始化项目容器Project Container在TESSY主界面点击File → New → Project弹出向导窗口。这里的关键选择是Project TypeStandard Project适用于大多数场景生成.tesproj文件支持C/C混合AUTOSAR Project仅当项目使用AUTOSAR 4.2且已配置好arxml描述文件时选用它会自动解析BSW模块接口Legacy Project兼容TESSY 3.x旧工程新项目严禁选用。注意Project Name不能含空格或特殊字符如My_Test_Project_v2合法My Test Project (v2)非法否则后续CI集成时Jenkins会因路径解析失败而中断。我建议统一用snake_case命名如bms_soc_calculation_test。创建后TESSY自动生成项目目录结构bms_soc_calculation_test/ ├── .tesproj # 项目元数据 ├── src/ # 存放被测源码.c/.h ├── test/ # 存放测试用例.tes └── build/ # 编译输出.elf, .map, .gcov此时不要急着导入代码先检查src/目录权限——Windows下若src/在OneDrive同步文件夹内TESSY可能因文件锁报错Access denied。解决方案将整个项目移到C:\tessy_projects\这样的本地路径。3.2 步骤二导入被测代码Import SUT Code右键项目名→Import → General → File System选择你的.c和.h文件。关键动作是勾选Create links in workspace在工作区创建链接而非复制文件。原因有三保持与原始代码库的实时同步你在Git里改了calc_soc.cTESSY里立刻生效无需重新导入避免头文件路径混乱复制文件会破坏原有#include driver/gpio.h的相对路径而链接保留原始路径结构支持增量更新右键项目→Refresh即可同步最新修改。但有个隐藏陷阱若.h文件中有#include ../config.h而config.h不在导入路径内TESSY会报错Cannot resolve include file。此时不能手动复制config.h而应右键项目→Properties → C/C General → Paths and Symbols → Includes添加../config路径。记住TESSY的头文件路径是“解析时”生效不是“编译时”生效所以必须在这里配而非在编译器设置里。3.3 步骤三配置编译器与链接器Toolchain Setup这是耗时最长也最容易出错的步骤。进入Project → Properties → ToolchainCompiler选择你的交叉编译器如ARM GCC并确认Version与实际安装一致Compiler Executable点击Browse找到arm-none-eabi-gcc.exe务必取消勾选Use defaultAdditional Compiler Flags粘贴项目真实的编译选项如-mcpucortex-m4 -mfloat-abihard -mfpufpv4 -O1 -g3 -WallInclude Paths点击Add逐条添加头文件路径注意这里添加的是-I参数的路径与步骤2.2中的Paths and Symbols是两套系统必须同时配置LinkerLinker Executable指向arm-none-eabi-gcc.exeTESSY用GCC同时做编译和链接Library Search Path添加.a库路径Libraries添加-lc -lm等基础库。踩坑实录某客户使用NXP S32K144其SDK要求链接-lS32K144_RGM库。但TESSY的Libraries框里填S32K144_RGM会失败必须填全名S32K144_RGM.a。原因是TESSY底层调用GCC时会自动加lib前缀和.a后缀填S32K144_RGM会去找libS32K144_RGM.a而实际库名是S32K144_RGM.a。解决方案在Libraries里直接填S32K144_RGM.a。3.4 步骤四生成测试HarnessHarness Generation右键.c文件→Generate Test Harness。TESSY会弹出对话框关键选项是Harness TypeStandard Harness标准用于普通函数Interrupt Harness中断用于__attribute__((interrupt))函数如CAN接收ISRFunction Selection勾选要测试的函数可多选TESSY会为每个函数生成独立HarnessStub Generation勾选Generate stubs for undefined functionsTESSY会自动为未实现的函数如HAL_UART_Transmit生成空桩stub避免链接失败。生成后test/目录下会出现function_name_harness.tes文件。此时不要急着运行先双击打开检查TESSY自动生成的Harness代码——它位于Generated Code标签页。重点看三处输入参数初始化如int16_t rpm 0;确认类型与.h中声明一致函数调用行如calc_soc(rpm, soc);确认指针参数soc传递正确输出捕获如int32_t soc_value soc;确认TESSY把*output解引用后赋给了局部变量。若发现类型错误如.h中是uint16_tHarness里生成int说明步骤2.2的头文件路径没配全需回退修正。3.5 步骤五编写测试用例Test Case Authoring双击function_name_harness.tes进入测试用例编辑器。TESSY提供三种编写模式Table View表格视图最常用以Excel表格形式填写输入值、期望值、备注。例如测试calc_socInput_rpmInput_voltageExpected_socComment012000100满电状态3000950020低压报警Script View脚本视图用TESSY专有脚本语言类似JavaScript编写复杂逻辑如循环测试100组随机输入Graphical View图形视图拖拽信号发生器、数学运算块、比较器构建信号流图适合测试状态机或滤波算法。实操心得新手务必从Table View起步。但要注意一个反直觉细节——表格里的“Input_rpm”列名必须与Harness代码中定义的变量名完全一致区分大小写。若Harness里是int16_t input_rpm;表格列名就不能写RPM否则TESSY运行时报错Variable RPM not found。我建议在生成Harness后立即切换到Generated Code标签页复制变量名到表格列头杜绝拼写错误。3.6 步骤六编译与执行测试Build Run点击工具栏Build按钮锤子图标TESSY启动编译。观察底部Console视图若出现Build finished successfully说明Harness编译通过若报错undefined reference to HAL_GPIO_WritePin说明该函数未被stub需右键项目→Generate Stubs勾选缺失函数若报错section.bss will not fit in regionRAM说明测试数据过大需在Toolchain → Linker → Memory Regions中调大RAM区域。编译成功后点击Run按钮绿色三角TESSY启动仿真器默认QEMU也可配J-Link。测试结果在Test Results视图中显示Passed绿色输入输出完全匹配Failed红色实际输出与期望不符双击可查看详细差异如Expected: 100, Actual: 98Error橙色Harness执行异常如除零、空指针此时需检查被测代码健壮性。关键技巧首次运行失败时不要急着改代码先点击Debug按钮虫子图标TESSY会启动GDB调试器你可以在Harness的main()函数里设断点单步跟踪calc_soc()的每一步执行——这才是定位嵌入式C代码逻辑错误的黄金方法。4. 单元测试与集成测试的分水岭何时该把多个.c文件塞进一个工程很多工程师困惑我的motor_control.c调用了pwm_driver.c和adc_read.c该建一个测试工程还是三个答案取决于测试目标的抽象层级。TESSY对此有清晰的工程划分逻辑我用一张表说明本质区别维度单元测试工程Unit Test Project集成测试工程Integration Test Project测试对象单个.c文件内的函数如calc_torque()多个.c文件组成的模块如MOTOR_CTRL_MODULE代码可见性只导入被测.c和其直接依赖的.h如motor_control.h导入所有参与集成的.cmotor_control.c,pwm_driver.c,adc_read.c及公共.hmotor_interface.hStub策略对所有外部依赖函数生成stub如HAL_TIM_PWM_Start()不生成stub让真实函数参与执行但需确保其不触发硬件如HAL_TIM_PWM_Start()在stub中空实现Harness类型Standard Harness单函数调用Module Harness多函数协同调用需手动编写调用序列典型用例“当输入rpm2000时calc_torque()返回值是否在±5%误差内”“执行motor_start()后pwm_driver是否正确配置了TIM1通道”认证价值满足ISO 26262对“软件单元验证”的要求满足ASPICE对“集成测试”的过程域要求举个真实案例某EPS电动助力转向项目steering_control.c包含compute_assist_torque()函数它调用get_vehicle_speed()来自can_rx.c和get_steering_angle()来自adc_read.c。我们拆分为两个工程单元测试工程只导入steering_control.c为get_vehicle_speed()和get_steering_angle()生成stub输入值由表格直接设定如get_vehicle_speed() returns 60。目标是验证算法核心逻辑。集成测试工程导入steering_control.c、can_rx.c、adc_read.c但can_rx.c中的HAL_CAN_Receive()被stub为空adc_read.c中的HAL_ADC_Start()也被stub。然后创建Module Harness手动编写调用序列// Module Harness 伪代码 void test_steering_integration() { // 1. 模拟CAN接收速度数据 mock_can_rx_data.speed 60; // 2. 模拟ADC读取转角 mock_adc_data.angle 15; // 3. 执行主控函数 compute_assist_torque(); // 4. 验证PWM输出 ASSERT_EQUAL(expected_pwm_duty, pwm_output_duty); }注意TESSY的集成测试不是“自动拼接”它要求你显式声明模块边界。在集成工程中右键项目→Properties → Integration → Module Definition勾选参与集成的所有.c文件并指定Main Function即测试入口函数。若漏选can_rx.cTESSY会报错Symbol mock_can_rx_data not defined因为它只编译你勾选的文件。这种分离带来的好处是单元测试可由算法工程师独立完成无需懂CAN协议集成测试则由系统工程师主导需理解模块间交互。两者测试报告可分别提交给功能安全经理和ASPICE评估师各取所需。5. 调试失败用例的“五层剥洋葱法”定位速度提升300%当TESSY测试报告里出现Failed新手常陷入“改一行跑一次再失败”的死循环。我总结了一套结构化调试法按优先级从外到内五层剥离90%的问题能在前三层解决。5.1 第一层检查测试用例本身Test Case Sanity Check这是最快排除的层。双击失败用例在Table View中确认输入值是否超出函数设计范围如calc_soc()要求voltage在9000~16000mV但表格填了5000函数内部有if(voltage 9000) return 0;结果Expected_soc0却填了10期望值是否计算错误比如rpm0时算法理论输出soc100但你填了99TESSY严格比对判为失败数据类型是否隐式转换表格里填100Harness生成int32_t expected_soc 100;但函数返回uint8_t实际存储为0x64TESSY比对时按int32_t解释为100看似正确——但若填256uint8_t会溢出为0TESSY比对2560失败。实操技巧在Table View右键列头→Format Column为Expected_soc列设置Format: Decimal, Min: 0, Max: 100TESSY会自动高亮超限值。5.2 第二层审查Harness生成逻辑Harness Inspection切换到Generated Code标签页逐行检查输入初始化确认Input_rpm等变量赋值与表格值一致。常见错误是TESSY把uint16_t识别为unsigned int导致rpm65535时unsigned int赋值正常但uint16_t实际存储为0高位截断函数调用参数确认指针参数传递正确。如函数声明void calc_soc(uint16_t rpm, uint8_t* soc)Harness里必须是calc_soc(input_rpm, soc_value);若误写为calc_soc(input_rpm, soc_value);会触发未定义行为输出捕获方式确认TESSY捕获的是最终结果。如函数内部分配uint8_t* temp malloc(1); *temp 50; return temp;TESSY无法捕获*temp必须改用输出参数。提示TESSY 4.5新增Harness Validation功能右键Harness→Validate Harness它会静态检查参数类型匹配、指针解引用合法性等比手动检查快10倍。5.3 第三层单步调试被测代码Source-Level Debugging点击Debug按钮TESSY启动GDB会话。关键操作在Harness的main()函数第一行设断点按F5运行当执行到calc_soc(input_rpm, soc_value);时按F5进入函数内部在被测函数关键行如soc lookup_table[rpm_index];设断点观察rpm_index计算是否正确使用View → Expressions添加监视表达式如soc_value看指针地址、*(soc_value)看解引用值。我曾调试一个CAN ID过滤失败问题发现rpm_index计算中rpm/100整除导致索引偏移。在Expressions视图里输入(int)(input_rpm/100.0f)结果为29而input_rpm2950时整除得29但查表需要30——问题根源在此。5.4 第四层检查Stub行为Stub Behavior Audit若函数调用外部模块如HAL_UART_Transmit其stub是否按预期工作右键项目→Stubs → Edit Stub Implementation打开stub文件确认stub函数签名与原始声明一致参数类型、const修饰符检查stub内部逻辑如HAL_UART_Transmit的stub应返回HAL_OK而非HAL_ERROR对于有输出参数的stub如HAL_ADC_GetValue(ADC_HandleTypeDef* hadc, uint32_t* pData)stub必须给*pData赋值否则被测代码读到垃圾值。常见陷阱HAL_Delay(uint32_t Delay)的stub若为空被测代码会瞬间执行完导致时序相关逻辑如“等待ADC转换完成”失效。正确stub应模拟延时for(volatile int i0; iDelay*1000; i);。5.5 第五层分析编译器优化影响Compiler Optimization Impact当以上四层都无问题但Debug模式下结果正确、Release模式下失败大概率是编译器优化捣鬼。在Project → Properties → Toolchain → Compiler中将Optimization Level从-O2降为-O1重新编译测试若问题消失说明优化触发了未定义行为如int* p NULL; *p 1;在-O2下被编译器优化掉-O1下仍执行使用volatile关键字标记易被优化的变量如volatile uint32_t flag 0;在TESSY的Test Results中右键失败用例→Show Assembly对比-O1和-O2下的汇编差异定位被优化掉的关键指令。这套方法让我在某次ADAS项目中将一个偶发失败用例的定位时间从8小时压缩到25分钟。关键是按顺序排查不跳层——很多工程师一上来就开GDB结果在无关代码里浪费半天。6. 从TESSY工程到CI/CD流水线自动化测试的落地脚手架TESSY的价值不仅在于桌面端测试更在于它能无缝融入现代DevOps流水线。我为多家客户搭建的CI方案核心是用TESSY命令行工具tessycli替代GUI操作让测试成为Git Push后的自动环节。6.1 tessycli基础命令链从建工程到出报告TESSY安装目录下有tessycli.exeWindows或tessycliLinux它支持全功能命令行操作。一个完整的自动化流程如下# 1. 创建新工程基于模板 tessycli --create-project --name bms_test --type standard --path C:/ci_projects/ # 2. 导入源码支持通配符 tessycli --import-source --project C:/ci_projects/bms_test.tesproj --files src/*.c,src/*.h # 3. 配置编译器JSON格式配置文件 tessycli --set-toolchain --project C:/ci_projects/bms_test.tesproj --config toolchain_config.json # 4. 生成Harness指定函数 tessycli --generate-harness --project C:/ci_projects/bms_test.tesproj --functions calc_soc,calc_torque # 5. 运行测试生成JUnit格式报告供Jenkins解析 tessycli --run-test --project C:/ci_projects/bms_test.tesproj --output-format junit --output-file test-report.xml其中toolchain_config.json内容示例{ compiler: ARM GCC, compiler_path: C:/gcc9/bin/arm-none-eabi-gcc.exe, flags: [-mcpucortex-m4, -O1, -g3], include_paths: [C:/sdk/inc, C:/rtos/cmsis] }注意tessycli要求Java 11运行时且TESSY许可证必须是网络版Floating License因为命令行模式会占用一个浮动许可。若用节点锁定版Node-Locked需在CI服务器上安装TESSY GUI并激活。6.2 Jenkins集成实战三步配置零失败在Jenkins中创建TESSY-Test任务源码管理配置Git仓库Branch Specifier填*/develop确保每次合并到develop分支就触发测试构建环境在Build步骤中选择Execute Windows batch command粘贴echo off set TESSY_HOMEC:\Program Files\TESSY\4.5 set PATH%TESSY_HOME%\bin;%PATH% tessycli --create-project --name bms_test --type standard --path %WORKSPACE% tessycli --import-source --project %WORKSPACE%\bms_test.tesproj --files src/*.c,src/*.h tessycli --set-toolchain --project %WORKSPACE%\bms_test.tesproj --config %WORKSPACE%\toolchain_config.json tessycli --generate-harness --project %WORKSPACE%\bms_test.tesproj --functions calc_soc tessycli --run-test --project %WORKSPACE%\bms_test.tesproj --output-format junit --output-file %WORKSPACE%\test-report.xml测试报告在Post-build Actions中勾选Publish JUnit test result reportTest report XMLs填test-report.xml。这样配置后每次git pushJenkins自动拉取代码、创建TESSY工程、运行测试并在Jenkins界面直观显示通过率、失败用例详情、趋势图。某客户实施后回归测试时间从2小时缩短到8分钟且所有测试记录可审计、可追溯。6.3 报告深度利用不只是“Pass/Fail”更是质量仪表盘TESSY生成的test-report.xmlJUnit格式只是起点。我们进一步用Python脚本解析生成质量仪表盘import xml.etree.ElementTree as ET import pandas as pd tree ET.parse(test-report.xml) root tree.getroot() # 提取每个用例的执行时间、状态、失败原因 data [] for testcase in root.findall(.
返回列表