前言
在 git pre-push hook 实践一二 一文中,我们实践了如何使用pre-hook执行单元测试以影响push操作的结果。但这种方式也有不少缺点,如无法hook pr,无法在提交版本里记录和共享显示测试的结果。Travis CI作为github官方支持的service,免费为开源项目提供了一个优秀的持续集成环境。关于Travis CI的简介和使用,可以参考这篇 EyreFree: 利用 Travis CI 让你在 GitHub 上的 Xcode 项目持续构建。下面,我们将简介如何集成iOS的单元测试和测试的代码覆盖率工具。
单元测试
我们已经知道,在工程目录下执行xcodebuild test
命令,可以启动xcode 的单元测试,在持续集成环境下依然如此。在根目录的.travis.yml
文件中配置相关操作。
.travis.yml
osx_image: xcode9
language: objective-c
cache: cocoapods
podfile: Example/Podfile
env:
global:
- LANG=en_US.UTF-8
- LC_ALL=en_US.UTF-8
- WORKSPACE_NAME=`sudo find ./Example -name "*.xcworkspace" -maxdepth 1 |while read var; do echo $(basename $var .xcworkspace); done`
# the file named '*.xcworkspace' should be created by 'pod lib create...'
before_install:
- gem install xcpretty --no-rdoc --no-ri --no-document --quiet
- gem install cocoapods --pre --no-rdoc --no-ri --no-document --quiet
#- gem install slather --pre --no-rdoc --no-ri --no-document --quiet
- pod install --project-directory=Example
- rvm use $RVM_RUBY_VERSION
script:
- set -o pipefail
- echo $WORKSPACE_NAME
#- xcodebuild -workspace "$XCODE_WORKSPACE" -scheme "$SCHEME" -configuration Debug clean build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO | xcpretty -c
#- xcodebuild -workspace "$XCODE_WORKSPACE" -scheme "$SCHEME" -configuration Release clean build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO | xcpretty -c
- xcodebuild test -enableCodeCoverage YES -workspace Example/$WORKSPACE_NAME.xcworkspace -scheme $WORKSPACE_NAME-Example -destination 'platform=iOS Simulator,OS=latest,name=iPhone 8' -destination 'platform=iOS Simulator,OS=10.3.1,name=iPhone 7' -destination 'platform=iOS Simulator,OS=9.3,name=iPhone 6s'
- pod lib lint --allow-warnings --verbose
after_success:
- slather
- bash <(curl -s https://codecov.io/bash) #-f Example/cobertura.xml -X coveragepy -X gcov -X xcode -t
- sleep 3
xcodebuild test
- xcodebuild test -enableCodeCoverage YES -workspace Example/$WORKSPACE_NAME.xcworkspace -scheme $WORKSPACE_NAME-Example
-destination 'platform=iOS Simulator,OS=latest,name=iPhone 8'
-destination 'platform=iOS Simulator,OS=10.3.1,name=iPhone 7'
-destination 'platform=iOS Simulator,OS=9.3,name=iPhone 6s'
以上代码会在三个不同的destination
上进行单元测试并产生代码覆盖率记录,iOS11可选择最新的系统版本,较旧版本可以在环境提供的列表中选择。对于cocoapods
创建的包含demo的库,可以使用sudo find ./Example -name "*.xcworkspace" -maxdepth 1 |while read var; do echo $(basename $var .xcworkspace); done
自动确定workspace的文件名及补全scheme
,这对统一快捷配置CI的yml文件是有益的,当然,我们也可以自己手动配置与工程名及路径相关的参数。
测试结果日志
pr操作页-check结果为成功
pr操作页-check结果为失败
test failed时,整体会exit with 0,check为失败。此外,pod lib lint
操作等也会影响check结果。这对审阅者合并pr有一定的参考意义。
测试的代码覆盖率
运行编写的测试用例时,可能存在以下情况: 某个方法的if/switch分支没有执行到,甚至某个类的整个方法未被调用。这就形成了
所谓的测试覆盖率问题,可靠有效的测试结果应该建立在足够高代码覆盖率的测试用例上。下面介绍三种查看测试覆盖率的方式。
1. xcode
当test设置勾上code coverage
或xcodebuild test -enableCodeCoverage YES
时,将产生覆盖率记录文件。
如上图,我们可以查看到所有文件的代码覆盖率。点击类名,可以查看到标红即未被覆盖到的代码。
2. Slather
Generate test coverage reports for Xcode projects & hook it into CI.
slather是一个专业用于xcode生成测试代码覆盖率报告的工具。安装可参见github。当我们运行单元测试后,可在根目录执行:
slather coverage --scheme LPDCNetwork-Example
--workspace Example/LPDCNetwork.xcworkspace Example/LPDCNetwork.xcodeproj
结果为:
也可以执行:
$ slather coverage --html --show
--scheme LPDCNetwork-Example --workspace ./LPDCNetwork.xcworkspace ./LPDCNetwork.xcodeproj
自动生成并打开html形式的覆盖率报告。
另外,可以调整工程目录结构和修改.slather.yml
文件配置,执行slather
在自定义目录下生成覆盖率的xml文件,可用于上传到一些覆盖率服务生成报告集成pr界面。可用--ignore
命令或yml文件ignre下配置忽略不计入平均覆盖率的文件路径。
.slather.yml
coverage_service: cobertura_xml
workspace: Example/PopoverObjC.xcworkspace
xcodeproj: Example/PopoverObjC.xcodeproj
scheme: PopoverObjC-Example
source_directory: Example/
output_directory: Example/
ignore:
3. codecov
codecov对github有着良好的支持,当我们在CI中执行完单元测试后,可执行如下代码自动上传xcode代码覆盖率文件,或者上传前文slather相关命令生成的xml文件。
bash <(curl -s https://codecov.io/bash) #-f Example/cobertura.xml -X coveragepy -X gcov -X xcode -t
日志:
3.93s$ bash <(curl -s https://codecov.io/bash)
==> Travis CI detected.
project root: .
Yaml not found, that is ok! Learn more at http://docs.codecov.io/docs/codecov-yaml
==> Processing Xcode plists
Found plist file at /Users/travis/Library/Developer/Xcode/DerivedData/PopoverObjC-byqecvztvcxucabbetxyjvpkugpa/Logs/Test/E6D08998-FE45-47F6-B63C-1A81F39A7CF5.xccoverage
==> Running gcov in . (disable via -X gcov)
==> Python coveragepy not found
==> Searching for coverage reports in:
+ .
-> Found 4 reports
==> Detecting git/mercurial file structure
==> Appending build variables
+ TRAVIS_OS_NAME
+ TRAVIS_RUBY_VERSION
==> Reading reports
+ ./344206B7-9176-4963-8C93-EE67C319FEE8.xccoverage.plist bytes=13127261
+ ./DD06A5DE-7636-4E63-BC90-A70235D4E1D2.xccoverage.plist bytes=222002
+ ./E6D08998-FE45-47F6-B63C-1A81F39A7CF5.xccoverage.plist bytes=221932
+ ./Example/cobertura.xml bytes=6036
==> Appending adjustments
http://docs.codecov.io/docs/fixing-reports
+ Found adjustments
==> Gzipping contents
==> Uploading reports
url: https://codecov.io
query: branch=testCI&commit=98933100ae86b02345de549f28783167d6ce3ebc&build=99.1&build_url=&name=&tag=&slug=Assuner-Lee%2FPopoverObjC&service=travis&flags=&pr=false&job=318459810
-> Pinging Codecov
-> Uploading
-> View reports at https://codecov.io/github/Assuner-Lee/PopoverObjC/commit/98933100ae86b02345de549f28783167d6ce3ebc
覆盖率报告:
覆盖率报告的信息还是很丰富的,可以得到每个commit的覆盖率数值,各个分支间的对比,相比于基准值的对比等。此外,我们同样可以在codecov.yml
文件中设置要忽略的文件路径,以得到更准确的平均覆盖率。
同样,在pr页面可以看到codecov的覆盖率概览报告。
通过CI集成单元测试及代码覆盖率、lint等结果信息到pull,pr页面,这对于代码审阅,控制代码质量有着一定的积极作用。
谢谢观看,水平有限,如有错误,请多指教。
参考资料:
https://juejin.im/post/5a32154e51882503dc53b976
https://github.com/SlatherOrg/slather