作者:京东批发 吴滔

本教程将应用北汽登录模块为例,一步一步和大家一起搭建单元测试用例,并在Bamboo上跑起来,最终测试后果和代码覆盖率会Bamboo上汇总。

模块名称:BQLoginModule,是通过iBiu创立的一个模块工程

一 建设单元测试Bundle

ProductName: BQLoginTests

二 测试代码编写

1 配置文件同步

如果咱们要在测试代码应用咱们在Pod里的类,须要同步 Targets Support Files/Pods-BQLoginTests/Pods-BQLoginTests.debug.xcconfig 文件的内容到 Targets Support Files/Pods-BQLoginUITests/Pods-BQLoginUITests.debug.xcconfig,间接内容copy就成了,只是每次用iBiu装置过后都要做这个操作,后续应用脚本实现同步:

2 测试代码编写

具体的编写我这里就过多介绍了,网上教程一大篇,这里就不多说了,如果没有做性能测试,这里能够把主动生成的 testPerformanceExample 屏蔽掉。

三 运行单元测试

用 command+u,或者菜单(product->test)执行,就能取得后果

后果在这里看:

实现以上操作,根本的单元测试就OK了

上面咱们用命令行来跑下单元测试,首先进入工程目录:

cd BQLoginModule/Example

执行如下命令:

xcodebuild test -UseModernBuildSystem=NO -configuration=Debug -workspace './BQLoginModule.xcworkspace' -scheme "BQLoginModule_Example" -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.2.2' 

请大家留神将 workspace/scheme /模拟器信息 批改为本人工程对应信息,就能够看到后果

四 代码覆盖率

1 单元覆盖率

在XCode关上覆盖率统计,咱们只关上咱们的库做代码笼罩就成了,Xcode 12.4在如下中央:

在Pod外面BQLoginModule设置 BuildSettings 查找 "cov" ,把 以下2项都设置为YES;

而后咱们跑下单元测试,就能够看到覆盖率后果了:

2 Bamboo报告

因为咱们须要在Bamboo上汇总覆盖率报告,这里咱们应用iBiu的一个高级个性:用 Podfile.custom 文件加载通用cocoapods的外网库来应用,具体见图:

这里咱们引入2个库: OCMock(单元测试必备的Mock库) XcodeCoverage(覆盖率统计的库)

退出这个文件后,须要应用 iBou重新安装下组件

做如下设置:

这个命令次要是生成XcodeCoverage的环境依赖 env.sh 咱们关上文件看下,文件门路如下

env.sh内容如下:

这里 OBJECT\_FILE\_DIR_normal 和 SRCROOT指向的是咱们Example工程,咱们是须要对Pods里的BQLoginModule里的代码做单元笼罩,这2个环境变量批改如下:

export OBJECT_FILE_DIR_normal ="/Users/cdwutao3/Library/Developer/Xcode/DerivedData/BQLoginModule-fvrzeicgcswucwfgjqweugauzxia/Build/Intermediates.noindex/Pods.build/Debug-iphonesimulator/BQLoginModule.build/Objects-normal"export SRCROOT="/Users/cdwutao3/Desktop/ut/BQLoginModule/BQLoginModule/Classes"

而后在Pods/XcodeCoverage目录新建 xmlout目录,并运行命令:

./getcov -x -s -o xmlout 

能够失去如下后果:

还能够查看哪些代码没被笼罩,和Bamboo后果对齐:

实现以上步骤,就实现了本地用命令号实现单元测试的所有步骤,上面咱们接着来看要在Bamboo上输入报告须要怎么做。

五 Bamboo操作

1 创立利用

这里要确保对应库和依赖的库 ,给 xn\_testdev\_ci账号开权限

2 新建流水线

抉择 “从零开始创立”

3 配置流水线

根底信息外面的抉择如下

须要用到以下四个原子:

“下载代码”--大家可先配置应用“下载代码-iBiu”这个原子,我用这个始终应用不胜利,所以间接用“下载代码”来手动配置:

“自定义脚本”--因为当初iOS的单元测试还没有对应的原子操作,所有咱们通过本人写脚本来实现:

“单元测试”--你没看错,就是用java的单元测试原子,咱们输入的后果和这个原子匹配,所以选他就成了

“GCC代码覆盖率”

其中“单元测试”和“代码覆盖率”的门路是能够批改的,这个能够依据本人的理论门路批改

4 自定义脚本

阐明:

1 下载代码和配置iBiu都是本人的命令行来做的,然而须要开始配置下git用户信息

2 开始我用命令行写全副命令,然而Bamboo的命令行规定会导致一些的shell指令的生效,所以我采纳把 shell命令 写到文件上传到git仓库,而后执行的形式来实现

3 后果转换会还会用到 ocunit2junit 和 xcpretty 这2个命令,如果这2个命令出错,请分割Bamboo共事帮助装置下

4 大家在写shell命令时,不晓得文件是否生成,能够多用 ls 来看目录下的文件

5 重点:

  • 为了手动装置iBiu配置,请将本机 ~/Library/Application Support/iBiu/BQLoginModule/下的2个文件 spec_sources 和 pod_setup 上传到git,我是copy到 Example/BQLoginModule/Resource目录下而后上传到git仓库,这个目录能够批改,而后批改对应shell 命令的目录就成了
  • iBiu建的git仓库默认会过滤一些内容,批改 BQLoginModule 工程目录下的 .gitignore 文件,须要上传xcworkspacedata内容

  • 代码覆盖率设置,XcodeCoverage的阐明强调了不要用于AppStore的工程,为了防止线上事变,咱们通过命令来设置,不间接在工程里设置:

所以批改xcode的构建命令新加 GCC\_INSTRUMENT\_PROGRAM\_FLOW\_ARCS=YES GCC\_GENERATE\_TEST\_COVERAGE\_FILES=YES,命令如下:

xcodebuild -UseModernBuildSystem=NO -enableCodeCoverage=YES -configuration=Debug GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES -workspace "./${moduleName}.xcworkspace" -scheme "${moduleName}_Example" -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.2.2' test

5 Bamboo后果

覆盖率下载地址:

六 脚本会集

1 本地脚本

以BQLoginModule为例,最终本地脚本命令如下,大家能够从新找到本地目录执行查看成果:

git clone --depth=1 https://git.jd.com/BQMobileshop/BQLoginModule.gitcd BQLoginModule/Examplepod updatepwdmoduleName="BQLoginModule"testName="BQLoginTests"biu -pod install ./lsls ./Podsrm -f "./Pods/Target Support Files/Pods-${testName}/Pods-${testName}.debug.xcconfig"cp -f "./Pods/Target Support Files/Pods-${moduleName}_Example/Pods-${moduleName}_Example.debug.xcconfig"  "./Pods/Target Support Files/Pods-${testName}/Pods-${testName}.debug.xcconfig"cat "./Pods/Target Support Files/Pods-${testName}/Pods-${testName}.debug.xcconfig"xcodebuild clean -workspace "./${moduleName}.xcworkspace" -scheme "${moduleName}_Example"xcodebuild  -UseModernBuildSystem=NO -enableCodeCoverage=YES -configuration=Debug GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES -workspace "./${moduleName}.xcworkspace" -scheme "${moduleName}_Example" -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.2.2'  test  > utlogfile.txtcat utlogfile.txt |grep ".xcresult" > utlogpath.txtlogStr=$(cat ./utlogpath.txt)logPath=${logStr:1}if [ -z "$logPath" ]; then    exit 1fised "s/${moduleName}.build\/Debug-iphonesimulator\/${moduleName}_Example.build/Pods.build\/Debug-iphonesimulator\/${moduleName}.build/g" ./Pods/XcodeCoverage/env.sh> cov_env1.txtsed "s/${moduleName}\/Example/${moduleName}\/${moduleName}\/Classes/g" ./cov_env1.txt > cov_env2.txtcp -f ./Pods/XcodeCoverage/env.sh ./Pods/XcodeCoverage/env_bak.shrm -f ./Pods/XcodeCoverage/env.shcp ./cov_env2.txt ./Pods/XcodeCoverage/env.shcat "./utlogfile.txt"|ocunit2junitls test-reportscp ./cov_env2.txt ./Pods/XcodeCoverage/env.shmkdir xmlout./Pods/XcodeCoverage/getcov -x -o xmloutls ./xmlout/lcovcat "./utlogfile.txt"|xcpretty -t -r html --output testresult/testresult.htmlls te

2 Bamboo脚本

Bamboo脚本分成2局部,一个是在Bamboo上执行的脚本

rm -fr "/Users/admin/Library/Application Support/iBiu/BQLoginModule"mkdir "/Users/admin/Library/Application Support/iBiu/BQLoginModule"rm -fr ./BQLoginModulegit clone --depth=1 https://git.jd.com/BQMobileshop/BQLoginModule.gitcd BQLoginModule/Examplecp "./BQLoginModule/Resource/spec_sources" "/Users/admin/Library/Application Support/iBiu/BQLoginModule"cp "./BQLoginModule/Resource/pod_setup" "/Users/admin/Library/Application Support/iBiu/BQLoginModule"ls "/Users/admin/Library/Application Support/iBiu/BQLoginModule"biu -pod install ./sh UT.sh

脚本剩下局部写入 UT.sh,放在BQLoginModule/Example目录下, 而后上传到git仓库来执行,大家做的时候留神批改变量名称:

pwdmoduleName="BQLoginModule"testName="BQLoginTests"ls ./Podsrm -f "./Pods/Target Support Files/Pods-${testName}/Pods-${testName}.debug.xcconfig"cp -f "./Pods/Target Support Files/Pods-${moduleName}_Example/Pods-${moduleName}_Example.debug.xcconfig"  "./Pods/Target Support Files/Pods-${testName}/Pods-${testName}.debug.xcconfig"cat "./Pods/Target Support Files/Pods-${testName}/Pods-${testName}.debug.xcconfig"xcodebuild clean -workspace "./${moduleName}.xcworkspace" -scheme "${moduleName}_Example"xcodebuild  -UseModernBuildSystem=NO -enableCodeCoverage=YES -configuration=Debug GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES -workspace "./${moduleName}.xcworkspace" -scheme "${moduleName}_Example" -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.2.2'  test  > utlogfile.txtcat utlogfile.txt |grep ".xcresult" > utlogpath.txtlogStr=$(cat ./utlogpath.txt)logPath=${logStr:1}if [ -z "$logPath" ]; then    exit 1fised "s/${moduleName}.build\/Debug-iphonesimulator\/${moduleName}_Example.build/Pods.build\/Debug-iphonesimulator\/${moduleName}.build/g" ./Pods/XcodeCoverage/env.sh> cov_env1.txtsed "s/${moduleName}\/Example/${moduleName}\/${moduleName}\/Classes/g" ./cov_env1.txt > cov_env2.txtcp -f ./Pods/XcodeCoverage/env.sh ./Pods/XcodeCoverage/env_bak.shrm -f ./Pods/XcodeCoverage/env.shcp ./cov_env2.txt ./Pods/XcodeCoverage/env.shcat "./utlogfile.txt"|ocunit2junitls test-reportscp ./cov_env2.txt ./Pods/XcodeCoverage/env.shmkdir xmlout./Pods/XcodeCoverage/getcov -x -o xmloutls ./xmlout/lcovcat "./utlogfile.txt"|xcpretty -t -r html --output testresult/testresult.htmlls test

七 谬误速查

这里会集了在写脚本时的一些谬误,不便大家查看

1 不能在测试工程援用本人的代码

请参看 二--1 ”配置文件同步“ 解决

2 在Bamboo上的Pods文件夹,没有拉到iBiu的其余配置信息

请参看 五--4 ”自定义脚本“的重点 1 来解决

3 “No coverage data in result bundle”

请参看 五--4 ”自定义脚本”的重点 2 来解决

4 应用命令行跑单元测试时,始终提醒不能找到模拟器

-destination 'platform=iOS Simulator,name=iPhone 8,OS=13.2.2' 改为 -destination 'id=xxxxxxxxxx' 这种格局,id为屏幕提示

5 Bamboo Shell里提醒 “未设置原子执行条件”

因为Bamboo的Shell对字符拼接,变量的解决有限度,所以一部分shell命令最好放在文件执行

6 在本地测试时,Pods/XXXXModule的设置项在每次iBiu装置后都会重置

请留神手动批改,或者间接应用脚本运行

7 在本地测试时,代码覆盖率只蕴含了一部分源码文件,不是全副

请清空 ~/Library/Developer/Xcode/DerivedData 目录再测试一次

8 在Bamboo上发现有些库拉不下来

请确保 对应 库给xn\_testdev\_ci开了权限

9 覆盖率文件生成不了

请确保XXXTests的版本信息和主工程的XXXXModule_Example的版本信息统一