在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属性:
- 获取失败用例的name属性:匹配包含
failure子节点的testcase
failures=$(xmllint --xpath '//testsuite/testcase[failure]/@name' "$xml_file")
- 获取成功用例的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
相关产品推荐
相关产品推荐

