探究 Xcode 命令行用法二:xcodebuild 测试实践

article/2025/1/11 20:48:21

本文还是 adat 项目的延伸,瞄准开发周期的测试环节,主要介绍 Xcode 范畴内的测试概念和自动化测试实践,不会讨论如何编写高质量的测试用例。文中涉及到 Xcode 构建的许多概念,大部分已在前两篇文章中有所说明,建议先大致浏览一遍。



内容概览

  • Xcode 测试相关的概念
  • xcodebuild 命令中测试相关的用法
  • xcodebuild 测试实践
  • 存在的问题


Xcode 测试相关的概念

在开始测试之前,有必要简单介绍一下 Xcode 中测试相关的概念,这对于编写自动化测试命令非常重要。因为文中会反复提到这些概念,使用时也必须清楚这些概念之间的关系。


测试包

Test Bundle,专门用于测试的 Target。Xcode 13.1 新建项目时勾选 Include Tests 会自动创建单元测试包和 UI 测试包。测试包内组织了多个测试用例。


测试用例

Test Case,专门用于测试的类 Class,继承自 XCTestCase。在测试用例内导入需要测试的头文件,设置初始环境,并编写多个测试方法。


测试方法

Test Method,专门用于测试的方法,必须是实例方法且方法名必须以 test 开头且没有参数和返回值,否则不会被 Xcode 识别为测试方法,也就不会被自动调用。


单元测试

Unit Test,是一种测试维度,主要测试代码逻辑,粒度较细,依赖良好的架构设计并编写可测试的代码(Testable Code)。在测试方法中调用需要测试的代码,并用 XCTAssert 及相关方法来判断结果。


UI 测试

UI Test,在较粗维度上进行测试,模拟用户的操作。Xcode 用 UI Test Recorder 来记录操作序列,自动将序列以代码的形式插入到测试方法中,运行测试方法就是把序列“重放”一次,以观察同样的操作在不同设备环境上的表现。UI 测试可以在需要的位置进行截屏,保留现场。


测试计划

Test Plan,一个以 .xctestplan 为扩展名的 JSON 格式文件,组合了测试包和配置(Configuration),可以分别设置测试包、测试用例、测试方法是否启用以决定是否参与测试,配置包含一个默认配置和多个自定义配置,大部分配置项来自于 Scheme。自定义配置未指定的配置项由默认配置的对应配置项决定。

在 Scheme Manager 中,可以将 Scheme 转为测试计划,也可以在 Xcode -> Product -> Test Plan 创建新的测试计划。对于大型项目,建议将 Scheme 转为测试计划,因为测试计划包含更多配置项,比如启用测试超时、重复测试等,而且 JSON 文件比 Scheme 更易于版本管理。

必须要为测试计划创建至少一个自定义配置,否则测试计划内的任何测试都将无法运行。在将 Scheme 转为测试计划时,Xcode 帮我们自动完成了这个操作。你也可以添加额外的自定义配置。

在这里插入图片描述
在这里插入图片描述

测试报告

Test Reports,列出了每个测试用例的测试结果:执行步骤、耗时、截屏、日志等。
在这里插入图片描述

代码覆盖率

Code Coverage,显示测试用例覆盖了多少代码,Xcode 提供了可视化界面,可据此来完善测试用例。启用代码覆盖率并执行测试后,代码编辑器右边缘就会显示某行被测试的次数。
在这里插入图片描述



xcodebuild 命令中测试相关的用法

了解完测试相关的概念,结合 探究 Xcode 命令行用法一:Xcode 构建必备认知 一文对命令行的认知,就可以对 xcodebuild 测试命令进行分析了。在 Terminal 中执行man xcodebuild提取测试相关的选项,对每个选项和操作的用法说明如下:


多环境并行测试

-disable-concurrent-destination-testing
禁止在多个环境中并行测试。如果指定了多个环境,一个完成后再开始下一个。

-maximum-concurrent-test-device-destinations NUMBER
测试时如果指定了多个真机环境,同一时间最多在 NUMBER 个真机上执行。和-disable-concurrent-destination-testing互斥。如果未明确指定 NUMBER,理论上没有上限。

-maximum-concurrent-test-simulator-destinations NUMBER
测试时如果指定了多个模拟器环境,同一时间最多在 NUMBER 个模拟器上执行。和-disable-concurrent-destination-testing互斥。如果未明确指定 NUMBER,默认为 4。


多运行器平行测试

-parallel-testing-enabled YES|NO
是否启用平行测试。平行测试将测试用例(类)分发到不同的运行器(Runner)或进程中执行,以提高测试效率。单元测试的运行器通常是应用的一个实例,UI 测试的运行器是 Xcode 创建的一个自定义应用。

-parallel-testing-worker-count NUMBER
执行平行测试的运行器数量,会覆盖-maximum-parallel-testing-workers NUMBER指定的数量。

-maximum-parallel-testing-workers NUMBER
执行平行测试的运行器的最大数量。

-parallelize-tests-among-destinations
将平行测试分发到多环境中执行。如果启用了平行测试并指定在多个环境中测试,那么测试用例会被分发到多环境中执行,而不会将一套完整的测试在每一个环境中执行。


测试计划

-showTestPlans
显示 Scheme 关联的测试计划,需要和 -scheme 搭配使用。

-testPlan
执行测试时指定测试计划,只传测试计划文件名,不传 .xctestplan 后缀。需要和 -scheme 搭配使用。

-only-test-configuration
只测试指定的配置,参数为自定义配置名称,区分大小写。注意这是测试计划的配置,不是 Target 的 BuildSettings 的变体。

-skip-test-configuration
跳过对指定自定义配置的测试。


测试超时

-test-timeouts-enabled YES|NO
是否启用测试超时。

-default-test-execution-time-allowance SECONDS
一个测试方法的默认超时时间,单位秒,每 60 秒向上取整,即:小于 60 秒按 60 秒算,大于 60 秒但小于 120 秒按 120 秒算,以此类推,例如:SECONDS 等于 59,实际是 60;SECONDS 等于 61,实际是 120 。需要先启用测试超时:-test-timeouts-enabled YES。等同于 XCTestCase 实例的 executionTimeAllowance 的作用,另外测试计划中也可以配置默认超时时间。优先级从高到低依次是:

  1. XCTestCase 的 executionTimeAllowance 属性值
  2. xcodebuild 的 -default-test-execution-time-allowance 选项的参数值
  3. 测试计划的 Default Test Execution Time Allowance (s) 配置项的值
  4. 未指定则为默认值 600 秒。

-maximum-test-execution-time-allowance SECONDS
一个测试方法的最大超时时间,单位秒,每 60 秒向上取整。需要先启用测试超时:-test-timeouts-enabled YES。XCTestCase 实例并未提供相关属性或方法去设置,也没有默认最大超时时间,因此优先级从高到低依次是:

  1. xcodebuild 的 -maximum-test-execution-time-allowance 选项的参数值
  2. 测试计划的 Maximum Test Execution Time Allowance (s) 配置项的值

一个测试方法的超时时间由默认超时时间和最大超时时间的较小者决定。达到超时时间后,判定测试失败,并生成一个 Spindump 文件:
在这里插入图片描述
后续会有文章介绍如何解析 Spindump 文件。关注我,第一时间获取:virusbee - 本文作者


重复测试

-test-iterations <number>
重复测试<number>次。

-retry-tests-on-failure
测试失败后再次尝试,直到测试成功或达到总测试次数。总测试次数默认是 3 次,如果指定了-test-iterations <number>,则总次数为<number>次。不能和-run-tests-until-failure一起用。

-run-tests-until-failure
测试成功后再次运行,直到测试失败或达到总测试次数。总测试次数默认是 100 次,如果指定了-test-iterations <number>,则总次数为<number>次。不能和-retry-tests-on-failure一起用。

-test-repetition-relaunch-enabled YES|NO
是否每个测试都在新进程中执行,如果为 NO,所有的测试都将在同一个进程中执行。必须和-test-iterations <number>-retry-tests-on-failure-run-tests-until-failure搭配使用。


本地化测试

-testLanguage
指定测试语言,语言遵循 ISO 639-1 标准,例如 nl、hr、ar。

-testRegion
指定测试地区,地区遵循 ISO 3166-1 标准,例如 GN、KE、IT。


代码覆盖率

-enableCodeCoverage YES|NO
启用代码覆盖率


筛选测试用例

-only-testing:TEST-IDENTIFIER
只测试 TEST-IDENTIFIER 指定的测试,关于 TEST-IDENTIFIER 的详细说明,参见 TN2339: 使用 Xcode 命令行构建的常见问题 的如何利用命令行实施单元测试?

-skip-testing:TEST-IDENTIFIER
跳过 TEST-IDENTIFIER 指定的测试。


测试操作

test
执行测试。

build-for-testing
生成 .xctestrun 文件,作为test-without-building的参数。

test-without-building
利用build-for-testing生成的 .xctestrun 文件进行测试,通过-xctestrun选项来指定。

关于测试操作的详细用法,参见 TN2339: 使用 Xcode 命令行构建的常见问题 的如何利用命令行实施单元测试?如何利用命令行实现 Xcode 中的 Build For Testing 和 Test Without Building 功能?



xcodebuild 测试实践

测试需求

项目概况
一款 iOS 应用,最低支持 iOS 9.0;应用发行到香港、日本、韩国 3 个地区;支持简体中文、繁体中文、日语、韩语、英语 5 种语言;已有若干单元测试和 UI 测试用例,部分测试用例已整合为测试计划。

项目清单
项目路径:App.xcodeproj
Targets:App(主应用)、AppTests(单元测试包)、AppUITests(UI 测试包)
Scheme:App(配置测试计划)、AppTests(配置单元测试包和UI 测试包)
发行地区:香港 HK、日本 JP、韩国 KR
支持语言:简体中文 zh-Hans、繁体中文 zh-Hant、日语 ja、韩语 ko、英语 en
测试计划:Core.xctestplan(只有一个默认配置和一个自定义配置,配置项均为默认值)
单元测试包内的用例(类):AccountTests,DataTests,ParseTests,HelperTests(方法 testExample 无需测试)
UI 测试包内的用例(类):LoginTests,ChatTests,PaymentTests

现有设备

类型名称或IDOS
真机ID:4cbbc9c59cd4c29dad494141b81b2f64ab45d643iOS 15.1
真机ID:00004032-102044371DF4313AiOS 14.5.1
模拟器名称:iPhone 13 ProiOS 15.0
模拟器名称:iPhone SEiOS 13.5
模拟器名称:iPad ProiOS 12.4

测试要求
测试计划需要在每台设备上完整执行 10 次测试,直到失败为止,每个测试限制在 1 分钟内完成,模拟器最多同时开 2 个;其余测试用例采用平行测试,测试失败不停止,最多测试 10 次;输出代码覆盖率、测试报告、日志和失败截图。


需求分析及实现

根据测试要求,测试计划和其余测试用例分开执行,需要写两条命令。

对于测试计划Core.xctestplan,用-testPlan Core来指定;测试计划需搭配 Scheme 使用,而该测试计划配置在 App Scheme 下,即-scheme App;执行 10 次,即-test-iterations 10;直到失败为止,即-run-tests-until-failure;为了确保每次都在新进程中测试,添加-test-repetition-relaunch-enabled YES;每个测试限制在 1 分钟内完成,需要启用测试超时,即-test-timeouts-enabled YES,并将超时时间设置为 60 秒,即-maximum-test-execution-time-allowance 60;上表列出的每台设备都要参与测试,根据各自类型、名称、ID、版本来构造 -destination 参数值,有几台设备就写几个-destination;模拟器最多同时开 2 个,由于模拟器默认最多同时开 4 个,因此设置-maximum-concurrent-test-simulator-destinations 2;输出代码覆盖率,即启用代码覆盖率-enableCodeCoverage YES;为了方便获取代码覆盖率、测试报告等,将测试结果输出到指定的位置result1,即-resultBundlePath result1

完整命令:

$ xcodebuild test \
-project App.xcodeproj \
-scheme App \
-testPlan Core \
-test-iterations 10 \
-run-tests-until-failure \
-test-repetition-relaunch-enabled YES \
-test-timeouts-enabled YES \
-maximum-test-execution-time-allowance 60 \
-destination "platform=iOS,id=4cbbc9c59cd4c29dad494141b81b2f64ab45d643" \
-destination "platform=iOS,id=00004032-102044371DF4313A" \
-destination "platform=iOS Simulator,name=iPhone 13 Pro,OS=15.0" \
-destination "platform=iOS Simulator,name=iPhone SE,OS=13.5" \
-destination "platform=iOS Simulator,name=iPad Pro,OS=12.4" \
-maximum-concurrent-test-simulator-destinations 2 \
-enableCodeCoverage YES \
-quiet \
-resultBundlePath result1

思考一下,这个命令执行完成后,所有测试通过,一个普通的测试方法执行了几次?答案是 50 次。这是一个并行测试,因此测试计划会在每台设备上完整执行 10 次,有 5 台设备参与测试,测试计划只有 1 个自定义配置,即:10次 * 5设备 * 1配置 = 50 次。

对于其余测试用例,单元测试用例属于 AppTests 包,UI 测试用例属于 AppUITests 包,且两个包都配置在 AppTests Scheme 下,因此指定-scheme AppTests; AppTests 包内的 HelperTests 类的 testExample 方法无需测试,即-skip-testing:AppTests/HelperTests/testExample;最多测试 10 次,即-test-iterations 10;测试失败不停止,即-retry-tests-on-failure;采用平行测试,需先启用平行测试,即-parallel-testing-enabled YES,再将测试用例分到-destination中执行,即-parallelize-tests-among-destinations;其余配置和测试计划保持一致。

完整命令:

$ xcodebuild test \
-project App.xcodeproj \
-scheme AppTests \
-skip-testing:AppTests/HelperTests/testExample \
-test-iterations 10 \
-retry-tests-on-failure \
-destination "platform=iOS,id=4cbbc9c59cd4c29dad494141b81b2f64ab45d643" \
-destination "platform=iOS,id=00004032-102044371DF4313A" \
-destination "platform=iOS Simulator,name=iPhone 13 Pro,OS=15.0" \
-destination "platform=iOS Simulator,name=iPhone SE,OS=13.5" \
-destination "platform=iOS Simulator,name=iPad Pro,OS=12.4" \
-parallel-testing-enabled YES \
-parallelize-tests-among-destinations \
-enableCodeCoverage YES \
-quiet \
-resultBundlePath result2

思考一下,这个命令执行完成后,所有测试通过,一个普通的测试方法执行了几次?答案是 1 次。虽然最多执行 10 次,但如果第一次就执行成功,就不会再执行了,这是因为 -retry-tests-on-failure 只决定了测试失败的后续操作,而 -run-tests-until-failure 才是决定测试成功的后续操作,此处并未指定它,也无法指定它,两者是相互排斥的。如果第一次就执行成功,导致所有方法只测试了一次,那这个测试不充分,而测试需求就是这样要求,可以反推这个需求提的并不合理。


测试结果

测试结果保存在-resultBundlePath指定的路径,不能是已存在的路径。上述测试计划的测试结果是 result1.xcresult,其余测试用例的测试结果是 result2.xcresult。

双击 result1.xcresult 自动在 Xcode 中打开,查看测试结果:
在这里插入图片描述

代码覆盖率:
在这里插入图片描述



存在的问题

本地化

上面的命令还不够完善,无法支持多个地区和语言的测试要求,某些情况还要模拟地理位置,这应该如何处理?


将测试委托给第三方

如果测试任务繁重,又没有很多测试设备可用,往往需要将测试任务委托给第三方来完成,但又不能提供源码,这种情况该如何处理?


与持续构建系统结合

很多企业自己有持续构建系统,项目构建完成后会自动发邮件给关注者。直接把 .xcresult 文件通过邮件发送,是很不明智的做法,那如何自己解析 .xcresult 文件获取元数据,并生成自定义的测试报告、代码覆盖率界面呢?

限于篇幅,此处不展开说明,后续会有文章提供解决方案,关注作者第一时间获取。



精彩预告

本文概念非常多,实践部分也需要结合概念去写代码一步步验证,如果不太好理解,建议先收藏下来,慢慢消化。

下面是后续文章的计划(标题和顺序可能变动,以实际发布为准):

  • 探究 Xcode 命令行用法三:xcodebuild 打包
  • 探究 Xcode 命令行用法四:codesign 签名
  • 探究 Xcode 命令行用法五:上传与分发
  • 探究 Xcode 命令行用法六:Jenkins 持续构建
  • 探究 Xcode 命令行用法七:xcodebuild 测试相关问题解决方案

http://chatgpt.dhexx.cn/article/oWjnJTTV.shtml

相关文章

如何让php执行xcodebuild,Xcodebuild命令使用

Xcode-select命令 xcode-select是Mac系统自带的命令行工具&#xff0c;属于用户系统内/usr/bin。当电脑上安装多个Xcode时&#xff0c;xcode-select用来选择命令行工具为哪一个版本的Xcode服务。 命令行工具安装指令&#xff1a;xcode-select --install 选择指定的Xcode路径&am…

iOS 自动构建命令——xcodebuild

想想当初天天来到公司&#xff0c;每天需要做一件事就是打开Xcode打包ipa&#xff0c;上传到fir。日复一日月复一月年复一年的做着同样的事情&#xff0c;作为有志成为优秀工程师的我来说&#xff0c;这是必须要解决的问题&#xff0c;所以决定自动化解决问题。 简介 xcodebu…

iOS开发-思维导图(初级)

简介&#xff1a;本脑图只整理了一些自认为比较基础的东西&#xff08;比较主观&#xff09;&#xff0c;可能适用于部分初学者&#xff0c;对于正在进阶的小伙伴参考意义可能不大哦~&#x1f601; 如果有小伙伴觉得哪些知识也需要加到图中&#xff0c;欢迎评论区留言&#xff…

IOS开发之证书

分别为证书、appID、设备、描述文件 一、证书Certificates 证书类型&#xff1a; Software&#xff1a;开发证书&#xff08;程序员开发app&#xff09;、分发证书&#xff08;真机调试&#xff09;、发布证书&#xff08;正式发布&#xff09; Services&#xff1a;通知证书&…

怎么学习iOS,如何学习iOS开发?

近年来ios app开发在不断发展中,各中小型也如雨后春笋纷纷露头,像广州商侣软件公司这样的app开发企业可以说是处处可见,然而ios app开发到底该如何入手,如何才能如鱼得水般在这个领域里面畅游呢? 一、什么是ios app开发 ios app开发是指针对苹果公司所生产的手机的ios系统…

零基础学习 iOS 开发

作者&#xff1a;匿名用户 链接&#xff1a;https://www.zhihu.com/question/22000647/answer/114700565 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 作为一名混迹iOS开发圈近4年的码农&#xff0c;资历不深不浅&a…

IOS小白入门指南

加入ios 项目已经一个多月了&#xff0c;本篇文章主要介绍IOS开发入门的一些基础知识&#xff0c;帮助想学习iOS开发的人更有效率地学习。 目录 需要的计算机基础 开发语言选择 IOS两种开发语言的异同 Objective-C和swift的相同点&#xff1a; 二者的不同点&#xff1a…

java ios开发_使用Java开发iOS应用

自从使用Objective C开发原生的iOS应用以来,就有许多使用别的语言来开发iOS应用的替选方案。比如说,下面就列出了一些: PhoneGap, 使用HTML/JS来开发 RubyMotion,使用Ruby ionic,使用AngularJS开发 我最近发现的一个的是RoboVM,你可以通过它来用Java开 自从使用Objective…

IOS开发进阶学习资料(提升必备)

最近整理了下IOS学习资料&#xff0c;包含了入门、进阶、性能优化、面试和学习书籍&#xff0c;算是比较全面的&#xff0c;在这里分享给大家&#xff0c;希望对大家有用。 先晒出IOS学习路线图&#xff0c;大家照着图谱修炼。 学习社区 objc中国 learn IOS Ray Wenderlich…

iOS开发进阶(二):走近iOS原生开发

文章目录 一、前言二、知识储备三、 Object-C四、启动流程五、拓展阅读 一、前言 在应用 uni-app 进行跨平台APP开发过程中&#xff0c;发现并不支持视频播放小窗功能&#xff0c;且插件市场提供的插件用户体验不好&#xff0c;遂决定自行开发 uni-app 原生插件。 uni-app原生…

iOS开发学习系列(1)———Swift语言入门

缘起 对于成为全栈开发者的目标而言&#xff0c;很好奇自己几年前怎么就没想过iOS开发的事情。iOS好歹也是移动操作系统两巨头之一。反思了下&#xff0c;有可能是因为之前对Object-C太无感导致的。现在趁着Swift&#xff0c;借这个机会重新整理iOS的开发。本系列虽然是iOS开发…

IOS开发学习资料集合(开发必备)

最近整理了下IOS学习资料&#xff0c;包含了入门、进阶、性能优化、面试和学习书籍&#xff0c;算是比较全面的&#xff0c;在这里分享给大家&#xff0c;希望对大家有用。 先晒出IOS学习路线图&#xff0c;大家照着图谱修炼。 学习社区 objc中国 learn IOS Ray Wenderlich…

iOS开发学习路线

那么现在说正题,如何成为负责任的开发者? 关注作者:点击关注二字可以找到大神组织首先要负责,对自己的项目负责。如果是自己新开的项目,要保证随时都能清晰的想到项目当中每个地方是怎么实现的,测试或者用户反馈了问题以后,能立马想到可能的错误原因。 如果是接手的项目…

对项目需求管理的认识和体会

下面是对一位项目经理关于需求管理的访谈&#xff1a; 做了那么多个项目&#xff0c;我深深感到对项目的需求把握管理好了&#xff0c;是项目成功的关键。对需求的管理大概有那么几个活动&#xff0c;首先是需求获取&#xff0c;这是一个确定和理解客户的需要和期望的过程&…

项目范围管理:WBS

创建工作分解结构是把项目可交付成果和项目工作分解成较小的、更易于管理的组件的过程。工作分解结构&#xff08;WBS&#xff09;是项目管理的基础&#xff0c;项目的所有规划和控制工作都必须基于工作分解结构。如果没有工作分解结构&#xff0c;就谈不上项目的进度计划、成本…

项目治理-项目需求范围管理:范围蔓延、镀金

范围蔓延、镀金 场景1&#xff1a; “甲方需要做一个App电商系统&#xff0c;项目对接非常满意&#xff0c;快项目结尾的时候&#xff0c;甲方的老板说&#xff0c;听说现在流行小程序&#xff0c;这个电商系统一定要在小程序上面也可以运行&#xff0c;如果不支持&#xff0…

怎样使用GitLab管理项目?

1. issue 介绍 一般 master 分支默认是被锁住的&#xff0c;其目的是保护该分支。普通开发人员可以创建 issue 后建立对应的分 支然后去完成任务。完成issue 后便要合并分支&#xff0c;只需发送 merge request ,等待 owner 审核才能合并到 master 分支上。合并的过程中可能…

软件需求管理过程

软件需求管理过程 软件需求管理过程 软件需求管理的过程 需求确认(确认需求规格) 需求获取–>需求分析–>需求规格编写–>需求验证需求变更(开发过程中的需求管理) 需求获取&#xff0c;需求分析&#xff0c;需求规格编写&#xff0c;需求验证&#xff0c;需求变更…

项目管理——需求收集与管理

项目管理——需求收集与管理 VS 需求收集对于产品经理来说&#xff0c;都已经属于老生常谈了。在产品的立项和设计前需要先做需求调研&#xff0c;在这里我们就来谈谈如何进行需求收集和管理。 一、需求收集目的 需求收集的目的就是了解用户目前所需要的是什么&#xff0c;最迫…

项目管理--需求分析

项目管理-需求分析 一、需求分析概述软件需求分类 需求分析是什么? 二&#xff0c;需求分析的任务需求分析的任务主要有两个方面&#xff1a;需求分析的困难&#xff1a;需求分析过程需求管理 三&#xff0c;需求分析案例需求分析的过程包括&#xff1a;exp:需求陈述需求陈述中…