iOS项目的持续集成与管理
liuian 2025-08-05 19:29 25 浏览
当实现新功能时,如果忽略可维护性而引入技术债务,那将会需要延迟解决它或导致增加维护成本。
最近我们已经思考通过哪些方式来提高代码的质量:
- 当代码的质量下降时,通过设置一些工具来马上提醒开发者;
- 文档化一些编码规范和思考在过去的几个项目中如何避免维护性差的问题。
我将会简单地概括我们需要设置什么才能自动监控代码质量。
基础
我们选择一个持续集成工具Jenkins,让它运行在一台放在我们工作室的Mac Mini。其实我不怎么喜欢Jenkins,但到目前为止,它是最稳定和最适合的工具来完成这些工作。
我们已经通过Homebrew和rbenv来分别安装Jenkins和Ruby,而rbenv能够为我们提供一个最新和稳定的Ruby Gems环境。有个Homebrew和Ruby Gems两个包管理工具之后,我们就几乎能够安装所有我们需要的工具,但很少会破坏与原有OS X系统更新提供的Ruby。
单元测试
我们使用Specta和Expecta来测试我们的iOS项目。
Specta让我们采用行为驱动开发(BDD)风格的语法来编写测试,相比于XCTest的语法,它更加易读。它还有一个强大的分组测试功能,在测试之前或之后运行一些代码块,这样的话,能够极大地减少重复代码。
Expecta是一个匹配器框架,我们可以在测试中使用它来创建断言。它的语法非常强大,与此同时,它比内建的XCAssert套件更加易读。例如:
expect(@"foo").to.equal(@"foo"); expect(foo).notTo.equal(1); expect([bar isBar]).to.equal(YES); expect(baz).to.equal(3.14159);
我们在开发时,通过XCode来运行测试;而使用通过Homebrew来安装的Jenkins时,会借助XCTool。XCTool是一个可代替的选择来xcodebuild,它能让你通过命令行的方式来非常轻松地运行测试套件和生成JUnit风格的测试报告。
$ xctool -workspace Project.xcworkspace -scheme Project -reporter junit:junit-report.xml test
这些测试报告会发布在Jenkins上,而Jenkins会使用JUnit Plugin来根据时间的推移提供单元测试结果的图表,同时会向我们显示我们的测试是否稳定。
Unit Test
Pull Request测试
我们想我们的测试尽可能运行以至于如果我们破坏什么东西,我们就会马上知道。我们在feature branches做些修改,然后提交一个pull request到Github,那么代码就会被另一个开发者审查。只要被打开,我们就能运行所有的测试来确保没有任何东西被破坏。
当新的pull requst是开放状态时,为了管理这些,我们安装Github Pull Request plugin来将信息从Github发送到Jenkins。如果有任何测试失败,它将会显示在Github,然后我们就不将代码合并,直到代码被修复为止。
代码覆盖率
我们也会用Gcovr工具来生成代码覆盖率报告,Gcovr的安装方式也是Homebrew。你需要针对main target的debug congfiguration改变两个构建设置来配置项目。将Generate Test Coverage Files和Instrument Program Flow都设置为YES。
Code Coverage
当我们运行单元测试来生成代码覆盖率报告时,我们需要将OBJROOT=./build添加到XCTool命令行的尾部。
$ gcovr -r . — object-directory build/Project.build/Debug-iphonesimulator/Project.build/Objects-normal/x86_64 — exclude ‘.*Tests.*’ — xml > coverage.xml
Gcovr输出的代码覆盖率报告也会被插件Cobertura Jenkins plugin发布,这个插件会提供一种可视化的方式来根据时间的推移来显示代码覆盖率。
现在我们不仅可以看到测试是否通过,还可以看到代码的测试覆盖范围。
静态分析
在工具集中,其中一个强大并能够保持高质量的代码的工具就是静态分析工具。这些工具会扫描你的代码,然后生成一个报告,这个报告会告诉你破坏代码风格规则的代码位置。举几个规则的例子:
- 未使用的变量或参数
- 长变量名,方法名或代码行
- 覆盖一个方法,但没有在这个方法调用super
- 方法太长或方法过于复杂
- 还更多的规格...
我们使用OCLint静态分析工具,这个工具能够支持C,C++和Objective-C语言。OCLint通过结合XCTool使用来生成json-compilation-database reporter,从而提供great integration特性。我们首先添加另一个reporter到我们的XCTool命令行,然后将那个report传递到OCLint来执行静态分析。
$ xctool -workspace Project.xcworkspace -scheme Project -reporter junit:junit-report.xml -reporter json-compilation-database:compile_commands.json test $ oclint-json-compilation-database -e Pods -report-type pmd -o oclint-pmd.xml
这个report以PMD的方式来生成,然后使用PMD Plugin被发布到Jenkins。有了这些插件之后,你也可以在测试失败之前,设置每个警告的优先级(底,中,高)中一些限制。最初,我们设置这些限制为低,那么只要我们引入代码,就会被提醒,从而提高代码质量。
Static Analysis
自动部署
最后一个问题不是如何提高代码质量,而是如何节省时间。开发者通常都会将编译好的代码通过Crashlytics发送到设计师来设计审查,或在sprint结束演示时发给用户。发送一个已经编译好的App通常花一个开发者的10分钟左右时间,但它需要他们来切换任务和干扰他们的心流。
最近我们已经配置一个在夜晚构建系统,它会在早上自动发送一个新版本的App给每个人。
为了做到这样,我们使用fastlane。fastlane是一个定义lanes的一些操作来执行的强大工具集。现在我们有三个已经定义好的lanes,一个是用来发布给ribot开发者,一个是用来发布给在ribot的每个人,最后一个是发布给用户。
before_all do |lane|
cert
sigh
end
desc “Deploy a new build to ribot iOS developers over crashlytics”
lane :dev do
ipa
crashlytics({ groups: ‘ribot-developers’ })
end
desc “Deploy a new build to people at ribot over crashlytics”
lane :internal do
ensure_git_status_clean
append_build_time
ipa
crashlytics({ groups: ‘ribot’ })
reset_git_repo
end
desc “Deploy a new build to everyone over crashlytics”
lane :external do
ensure_git_status_clean
increment_build_number
ipa
crashlytics({ groups: [‘ribot’, ‘client’] })
commit_version_bump
add_git_tag
push_to_git_remote
end
after_all do |lane|
clean_build_artifacts
end通过使用fastlane工具(通过Ruby Gems来安装)来运行一个lane。
fastlane internal
在开始使用所有的lanes之前,我们应该自动确保我们有一个有效的signing certificate和最新的provisioning profile。所有我们的配置都放在一个.env文件,它让我们有些默认配置,但当我们运行fastlane根据需要来覆盖它们。
在将来,我们会通过使用deliver操作来自动化App Store提交过程。
最后总结
到目前为止,我们已经尝试这些过程,并在工程中呈现出好的结果。我们期望看到只要适当地使用这些工具,就能提高代码的质量,这些报告将会让我们随着时间推移来量化代码质量。我们期待在下一个工程中适当地使用这些工具会发生什么。
译者简介:刘耀柱(@Sam_Lau_13),iOS Developer兼业余Designer,参与开发技术前线iOS项目翻译,个人博客:
http://www.jianshu.com/users/256fb15baf75/latest_articles。
CSDN移动将持续为您优选移动开发的精华内容,共同探讨移动开发的技术热点话题,涵盖移动应用、开发工具、移动游戏及引擎、智能硬件、物联网等方方面面,如果您有想分享的技术、观点,可通过电子邮件(tangxy#csdn.net,请把#改成@)投稿。
第一时间掌握最新移动开发相关信息和技术,请关注mobilehub公众微信号(ID: mobilehub)。
相关推荐
- 手机一键还原(iphone手机一键还原)
-
如果你希望恢复华为手机上的一键锁屏功能,你可以按照以下步骤进行操作:1.进入设置:在你的华为手机上,打开设置应用程序。你可以在应用抽屉中找到该应用,通常是一个齿轮或者包含「设置」字样的图标。2.寻...
- 系统修复u盘(优盘系统修复)
-
1、我们在网络中,找到修复软件U盘烧录修复(PortFreeProductionProgram)v3.27,记得不需要太高级的版本,这个比较好用。 2、打开软件,出现的页面是,初始状态下,看到...
- sony笔记本u盘启动快捷键(索尼笔记本u盘快速启动键)
-
索尼笔记本按assist按键快捷键进入u盘启动索尼笔记本进入U盘启动的步骤:1、索尼笔记本位于键盘右上角有一个ASSIST的按键,首先按这个键就可以进入vaiocare的设置。2、通过按ASSIST...
- win7旗舰版密匙(正版win7旗舰版密钥)
-
一、Windows7旗舰版激活密钥零售版:Windows7UltimateRetail永久序列号【尝试联网激活,如果不能激活,可电话激活】[Key]:RHTBY-VWY6D-QJRJ9-JGQ...
- 一键ghost备份还原工具绿色版硬盘版
-
可以的。1.打开GHOST软件,接受许可协议,点击OK。2.从图像中选择Local→Partition→,3.选择镜像文件所在的分区,找到镜像文件(winxp.gho),然后单击enter。4.显示镜...
- 延缓写入失败电脑卡死(电脑显示延缓写入失败)
-
您好,请您检查下是否有人下载、网络电影等极大占据带宽的行为还有可能是您的地区网络和游戏服务器之间的网络衔接不佳,您可以使用一款网游加速器来解决希望对您有所帮助
- 手机变电脑桌面免费版(手机秒变电脑桌面下载破解版免费)
-
方法一、无需特别硬件,PC开热点手机连上即可投影,支持用PC的键鼠控制设备,如果是用来演示的话,这是解决方案之一。方法二、类似投影仪的原理这个需要设备制造商提供例如HDMI的输出支持,Android代...
- 惠普打印机墨盒怎么加墨水(惠普2622打印机怎么换墨盒)
-
惠普墨盒加墨水的步骤如下:确保墨盒已加满,取下墨盒。准备一张干净的纸,将墨盒放在上面。注意每个墨盒的顶上贴着一张胶纸,一般胶纸下面就会有注入墨水的孔。小心加墨一次挤入不能太多。如果打印墨色浅,可以在设...
- tplink无线路由器桥接教程(tplink路由器如何进行无线桥接)
-
步骤1:将扩展路由器插电源,不要插网线。步骤2:看易展路由器底部标签的SSID,打开手机的wifi设置,搜索这个wifi信号步骤3:链接上易展路由器的wifi信号步骤4:进入设置界面,部分手机可以自动...
- 怎样还原电脑原来的系统(咋样还原电脑系统)
-
首先,我们必须确保打开系统还原,否则无法恢复操作系统。在确保已打开的情况下,单击菜单,选择“附件”,点系统工具,并还原系统。接下来,打开系统还原,找到系统还原点,找到最佳适合系统还原的时间点,但确保系...
- 惠普服务中心电话(孚惠教育退费服务中心电话)
-
百脑汇里有两家鸿鹄的店面,电话分别是85133339/88609104
- win7装xp怎么装系统(windows7装xp)
-
Windows7和WindowsXP是两个不同的操作系统。但是安装的方法是相同的。第1种就是用安装盘。放入光驱以后。设置启动项以光驱优先,重启电脑,安装光盘,自动引导,按照提示一步一步的就可以安装...
- 磁盘不相邻怎么扩展卷(磁盘分区不相邻)
-
要扩展不相邻的磁盘,可以使用磁盘扩展技术,如磁盘阵列(RD)或逻辑卷管理(LVM)。RAID可以将多个磁盘组合成一个逻辑卷,提供更大的存储空间。LVM允许将多个物理卷组合成一个逻辑卷组,并在其中创建逻...
- 一周热门
- 最近发表
- 标签列表
-
- python判断字典是否为空 (50)
- crontab每周一执行 (48)
- aes和des区别 (43)
- bash脚本和shell脚本的区别 (35)
- canvas库 (33)
- dataframe筛选满足条件的行 (35)
- gitlab日志 (33)
- lua xpcall (36)
- blob转json (33)
- python判断是否在列表中 (34)
- python html转pdf (36)
- 安装指定版本npm (37)
- idea搜索jar包内容 (33)
- css鼠标悬停出现隐藏的文字 (34)
- linux nacos启动命令 (33)
- gitlab 日志 (36)
- adb pull (37)
- python判断元素在不在列表里 (34)
- python 字典删除元素 (34)
- vscode切换git分支 (35)
- python bytes转16进制 (35)
- grep前后几行 (34)
- hashmap转list (35)
- c++ 字符串查找 (35)
- mysql刷新权限 (34)
