基于分支文件变更执行移动端自动化测试的可持续方案咨询
基于变更文件选择性运行移动应用测试的方案
针对你的场景(Android用Compose UI测试、iOS用XCUITest,配合CircleCI、Git、Fastlane),以下是可行的现成工具和自定义实现方案:
现成工具选项
- CircleCI Path Filtering Orb + Fastlane:CircleCI官方的
path-filteringorb可以直接检测PR/分支中变更的文件路径,根据路径匹配结果触发不同的测试任务。你可以在Fastlane里提前定义好对应不同测试集的lane(比如对应iOS不同测试计划、Android不同测试套件的lane),然后让CircleCI根据路径匹配结果调用对应的lane。 - Danger:可以用
danger-swift(iOS)和danger-kotlin(Android)在PR阶段分析变更文件,通过编写简单的Ruby脚本逻辑,动态决定要运行的测试集,再调用Fastlane执行测试。不过这个需要你写一些自定义逻辑,灵活性更高但有一定配置成本。
自定义实现方案(更贴合你的现有工具链)
如果现成工具满足不了你的细分需求,可以自己基于Git、Shell脚本、Fastlane和CircleCI来搭建,核心思路是:先获取变更文件列表,再根据预设的路径-测试集映射规则,决定要执行的测试任务,最后用Fastlane和CircleCI完成执行。
1. 定义路径-测试集映射规则
在项目根目录创建一个test-mapping.yml配置文件,把代码路径和对应的测试集关联起来,示例:
android: - paths: ["app/src/main/java/com/example/home/", "app/src/test/java/com/example/home/"] test_suite: "com.example.home.HomeScreenTests" - paths: ["app/src/main/java/com/example/checkout/", "app/src/test/java/com/example/checkout/"] test_suite: "com.example.checkout.CheckoutFlowTests" ios: - paths: ["iOS/Modules/Home/", "iOS/Tests/HomeTests/"] test_plan: "HomeTestsPlan" - paths: ["iOS/Modules/Checkout/", "iOS/Tests/CheckoutTests/"] test_plan: "CheckoutFlowTestsPlan" # 基础模块变更时跑全量测试 global: - paths: ["app/src/main/java/com/example/core/", "iOS/Shared/"] android_test_suite: "all" ios_test_plan: "FullTestPlan"
2. 编写Shell脚本检测变更并输出测试集
在项目里加一个determine-tests.sh脚本,用来对比当前分支和主分支的差异,匹配对应的测试集:
#!/bin/bash set -e # 获取主分支(这里假设是main)与当前分支的变更文件列表 CHANGED_FILES=$(git diff --name-only origin/main...HEAD) # 安装yq用来解析YAML(CircleCI环境可以提前装) if ! command -v yq &> /dev/null; then sudo apt-get update && sudo apt-get install -y yq fi # 处理Android测试集 ANDROID_TEST_SUITES="" # 先检查全局规则 GLOBAL_ANDROID=$(yq e '.global[] | select(.paths[] | in(env.CHANGED_FILES)) | .android_test_suite' test-mapping.yml) if [ -n "$GLOBAL_ANDROID" ] && [ "$GLOBAL_ANDROID" = "all" ]; then ANDROID_TEST_SUITES="all" else # 匹配普通路径规则 for entry in $(yq e '.android[]' test-mapping.yml); do PATHS=$(echo "$entry" | yq e '.paths[]' -) for path in $PATHS; do if echo "$CHANGED_FILES" | grep -q "$path"; then SUITE=$(echo "$entry" | yq e '.test_suite' -) ANDROID_TEST_SUITES+=" $SUITE" break fi done done # 去重 ANDROID_TEST_SUITES=$(echo "$ANDROID_TEST_SUITES" | xargs | tr ' ' '\n' | sort -u | tr '\n' ' ') fi # 处理iOS测试集 IOS_TEST_PLANS="" GLOBAL_IOS=$(yq e '.global[] | select(.paths[] | in(env.CHANGED_FILES)) | .ios_test_plan' test-mapping.yml) if [ -n "$GLOBAL_IOS" ] && [ "$GLOBAL_IOS" = "FullTestPlan" ]; then IOS_TEST_PLANS="FullTestPlan" else for entry in $(yq e '.ios[]' test-mapping.yml); do PATHS=$(echo "$entry" | yq e '.paths[]' -) for path in $PATHS; do if echo "$CHANGED_FILES" | grep -q "$path"; then PLAN=$(echo "$entry" | yq e '.test_plan' -) IOS_TEST_PLANS+=" $PLAN" break fi done done IOS_TEST_PLANS=$(echo "$IOS_TEST_PLANS" | xargs | tr ' ' '\n' | sort -u | tr '\n' ' ') fi # 把结果写入环境变量,供后续任务使用 echo "export ANDROID_TEST_SUITES=\"$ANDROID_TEST_SUITES\"" >> $BASH_ENV echo "export IOS_TEST_PLANS=\"$IOS_TEST_PLANS\"" >> $BASH_ENV
3. Fastlane中定义测试执行Lane
Android Fastfile示例
lane :run_android_tests do |options| test_suites = options[:test_suites] if test_suites == "all" # 跑全量测试 gradle(task: "connectedDebugAndroidTest") else # 跑指定测试套件 test_suites.split(" ").each do |suite| gradle( task: "connectedDebugAndroidTest", flags: "--tests #{suite}" ) end end end
iOS Fastfile示例
lane :run_ios_tests do |options| test_plans = options[:test_plans] test_plans.split(" ").each do |plan| scan( scheme: "YourAppScheme", test_plan: plan, device: "iPhone 14", skip_build: false # 按需设置是否跳过构建 ) end end
4. CircleCI配置文件(.circleci/config.yml)
version: 2.1 jobs: detect-test-sets: docker: - image: cimg/base:stable steps: - checkout - run: name: Determine test suites/plans command: ./determine-tests.sh - persist_to_workspace: root: . paths: - $BASH_ENV run-android-tests: docker: - image: cimg/android:2023.04.1 steps: - checkout - attach_workspace: at: . - run: name: Run selected Android tests command: | if [ -n "$ANDROID_TEST_SUITES" ]; then fastlane run_android_tests test_suites:"$ANDROID_TEST_SUITES" else echo "No Android tests matched, skipping" fi run-ios-tests: macos: xcode: 14.3.1 steps: - checkout - attach_workspace: at: . - run: name: Run selected iOS tests command: | if [ -n "$IOS_TEST_PLANS" ]; then fastlane run_ios_tests test_plans:"$IOS_TEST_PLANS" else echo "No iOS tests matched, skipping" fi workflows: pr-test-workflow: jobs: - detect-test-sets: filters: branches: only: /pull\/.*/ - run-android-tests: requires: - detect-test-sets filters: branches: only: /pull\/.*/ - run-ios-tests: requires: - detect-test-sets filters: branches: only: /pull\/.*/
额外优化建议
- 如果没有匹配到任何测试集,可以设置默认跑核心的冒烟测试,避免完全跳过测试。
- 可以把
test-mapping.yml的规则拆分成Android和iOS各自的配置文件,方便维护。 - 在CircleCI中可以给测试任务设置缓存,加快构建和测试速度。
内容的提问来源于stack exchange,提问作者Codr
相关产品推荐
相关产品推荐

