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

在Bash脚本中用xmllint解析Android单元测试XML,区分成败用例

解决Android测试结果XML解析:区分成功/失败用例的XPath写法

问题背景

我在CircleCI上运行UI单元测试脚本,需要解析Android生成的测试结果XML,将成功测试用例存入一个列表,失败的存入另一个列表,之后遍历两个列表触发API调用,更新对应测试用例的工单(每个测试对应一个工单)。目前Bash脚本已完成部分逻辑,但不知道如何用XPath获取包含failure子标签的testcase的name属性,以及不包含failure子标签的testcase的name属性。

现有脚本片段:

totalTests=$(xmllint --xpath 'count(//testsuite/testcase)' $xml_file)
echo "Total tests = $totalTests"

# 此处需要获取包含failure子标签的testcase的name属性
failures=$(xmllint --xpath '//testsuite/testcase/????' $xml_file) 
echo "failures=$failures"

# 此处需要获取不包含failure子标签的testcase的name属性
successes1=$(xmllint --xpath '//testsuite/testcase/@name' $xml_file)
echo "successes1=$successes1"

IFS="$(printf '\nx')" && IFS="${IFS%x}";

for entry in $successes1
do
    number=`echo $entry | awk -F_ '{print $2}'`
    echo "CASE-$number"
done
...
# 失败用例遍历逻辑
...

测试结果XML示例:

<?xml version='1.0' encoding='UTF-8' ?>
<testsuite name="com.android.OnboardingBottomNavigation" tests="3" failures="1" errors="0" skipped="0" time="27.017" timestamp="2023-08-30T16:37:38" hostname="localhost">
  <properties>
    <property name="device" value="Pixel_4_API_33(AVD) - 13" />
    <property name="flavor" value="" />
    <property name="project" value=":app" />
  </properties>
  <testcase name="CASE_11447_Skip_Onboarding_Click_All_BottomNavs" classname="com.android.OnboardingBottomNavigation" time="5.483">
    <failure>java.lang.AssertionError: Expected value to be true.
at org.junit.Assert.fail(Assert.java:89)
at kotlin.test.junit.JUnitAsserter.fail(JUnitSupport.kt:56)
at kotlin.test.Asserter$DefaultImpls.assertTrue(Assertions.kt:648)
at kotlin.test.junit.JUnitAsserter.assertTrue(JUnitSupport.kt:30)
at kotlin.test.Asserter$DefaultImpls.assertTrue(Assertions.kt:658)
at kotlin.test.junit.JUnitAsserter.assertTrue(JUnitSupport.kt:30)
at kotlin.test.AssertionsKt__AssertionsKt.assertTrue(Assertions.kt:44)
at kotlin.test.AssertionsKt.assertTrue(Unknown Source:1)
at kotlin.test.AssertionsKt__AssertionsKt.assertTrue$default(Assertions.kt:42)
at kotlin.test.AssertionsKt.assertTrue$default(Unknown Source:1)
at com.android.OnboardingBottomNavigation.CASE_11447_Skip_Onboarding_Click_All_BottomNavs(OnboardingBottomNavigation.kt:39)</failure>
  </testcase>
  <testcase name="CASE_11445_Skip_Onboarding_Click_All_BottomNavs" classname="com.android.OnboardingBottomNavigation" time="15.353" />
  <testcase name="CASE_11446_Skip_Onboarding_Click_All_BottomNavs" classname="com.android.OnboardingBottomNavigation" time="2.513" />
</testsuite>

解决方案

核心XPath表达式

通过XPath的节点筛选语法,直接匹配目标testcase并提取name属性:

  1. 获取失败用例的name属性:匹配包含failure子节点的testcase
failures=$(xmllint --xpath '//testsuite/testcase[failure]/@name' "$xml_file")
  1. 获取成功用例的name属性:匹配不包含failure子节点的testcase
successes=$(xmllint --xpath '//testsuite/testcase[not(failure)]/@name' "$xml_file")

脚本优化:清理输出格式

xmllint输出的属性会带name="xxx"格式,需要用sed清理成纯名称字符串,方便后续提取工单编号:

# 处理失败用例,提取纯name值
failures=$(xmllint --xpath '//testsuite/testcase[failure]/@name' "$xml_file" | sed 's/name="\([^"]*\)"/\1/g')
# 处理成功用例,提取纯name值
successes=$(xmllint --xpath '//testsuite/testcase[not(failure)]/@name' "$xml_file" | sed 's/name="\([^"]*\)"/\1/g')

完整调整后的脚本片段

totalTests=$(xmllint --xpath 'count(//testsuite/testcase)' "$xml_file")
echo "Total tests = $totalTests"

# 获取并清理失败用例name
failures=$(xmllint --xpath '//testsuite/testcase[failure]/@name' "$xml_file" | sed 's/name="\([^"]*\)"/\1/g')
echo "失败用例: $failures"

# 获取并清理成功用例name
successes=$(xmllint --xpath '//testsuite/testcase[not(failure)]/@name' "$xml_file" | sed 's/name="\([^"]*\)"/\1/g')
echo "成功用例: $successes"

# 设置换行作为分隔符,避免用例名含空格时出错
IFS=$'\n'

# 遍历成功用例,触发API更新工单
for entry in $successes; do
    number=$(echo "$entry" | awk -F_ '{print $2}')
    echo "更新成功工单 CASE-$number"
    # 此处添加API调用逻辑,示例:
    # curl -X POST "your-api-endpoint?case=CASE-$number&status=success"
done

# 遍历失败用例,触发API更新工单
for entry in $failures; do
    number=$(echo "$entry" | awk -F_ '{print $2}')
    echo "更新失败工单 CASE-$number"
    # 此处添加API调用逻辑,示例:
    # curl -X POST "your-api-endpoint?case=CASE-$number&status=failed"
done

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 07:05:36