写在前面
之前记录了针对项目写UT的过程,最近在考虑把UT放到CI中。本文最终的结果是,写出脚本,放到Jenkins中,覆盖率达标后gerrit可加分。本文主要是记录自己的思考以及实操过程。干货的话,看这里
!!!相关脚本都是xcode11的,老的xcode版本生成的测试结果文件我没试过。
【SDK】作为SDK开发,如何开始编写第一个单元测试
【SDK】iOS对已有的项目写UT
【SDK】单元测试,XCTestCase,查看覆盖率
参考在文末,感谢分享人!
设想是这样的:提交代码gerrit触发Jenkins执行UT,执行打包(我是打的SDK的framework)
目前就是执行UT这块还没有自动化,就自己在xcode里手动执行。写到脚本里,无非就是xcodebuild 相关的
-
这里有个小插曲,就是因为自己手动执行的时候会启动一个simulator,有点烦,然后我就装了个xctool,等我真正试验xcodebuild跑测试的时候,发现不会启动simulator,那先不管这个了。把脚本写成就行
-
至于为啥用xcodebuild 我想说的是,因为这是果子自家的东西,只要好好弄,总归好用的。理论上,全家桶的东西,自圆其说是没有问题的。xcodebuild 使用点,参数位置无所谓在哪里,不分前后,你可以把action 参数写在这一行命令的任何部位,只要你的action 参数和后面跟的值对应好就行。
这叫action,后面说的都是执行一个action需要的参数
分析
- 脚本基本要求:
- 执行
- 代码覆盖率
- UT不过会让gerrit加分失败(没有使用gerrit的忽略这个)
- 高度配置化(算作优化先幻想一下)
我们先看下xcodebuild有哪些命令
之前有用到
xcodebuild - clean
xcodebuild -archive
xcodebuild -export
等等
那么这次我们继续找测试相关的,在命令行中输入man xcodebuild
然后可以在命令行看到这样的
然后往下翻
可以看到
test
命令,好,找到需要的了我先把这些和test相关的命令手动罗列出来,方便一会儿写脚本的时候使用,建议直接跳过这个表格,我是为了自己都认识一遍
para | value | description |
---|---|---|
-enableCodeCoverage | [YES / NO] | Turns code coverage on or off during testing. This overrides the setting for the test action of a scheme in a workspace. |
-xctestrun | xctestrunpath | Specifies test run parameters. Can only be used with the test-without-building action. Cannot be used with -workspace or -project. See <x-man-page://5/xcodebuild.xctestrun> for file format details. |
-testPlan | test-plan-name | Specifies which test plan associated with the scheme should be used for testing. Pass the name of the .xctestplan file without its extension. |
-skip-testing | test-identifier | Constrain test targets, classes, or methods in test actions. -only-testing constrains a test action to only testing a specified identifier, and excluding all other identifiers. -skip-testing constrains a test action to skip testing a specified identifier, but including all other identifiers. Test identifiers have the form TestTarget[/TestClass[/TestMethod]]. The TestTarget component of an identifier is the name of a unit or UI testing bundle as shown in the Test Navigator. An xcodebuild command can combine multiple constraint options, but -only-testing has precedence over -skip-testing. |
-only-testing | test-identifier | 同上,一起使用 |
-skip-test-configuration | test-configuration-name | Constrain test configurations in test actions. -only-test-configuration constrains a test action to only test a specified test configuration within a test plan, and exclude all other test configurations. -skip-test-configuration constrains a test action to skip a specified test configuration, but include all other test configurations. Each test configuration name must match the name of a configuration specified in a test plan and is case-sensitive. An xcodebuild command can combine multiple constraint options, but -only-test-configuration has precedence over -skip-test-configuration. |
-only-test-configuration | test-configuration-name | 同上,一起使用 |
-disable-concurrent-destination-testing | Do not run tests on the specified destinations concurrently. The full test suite will run to completion on a given destination before it begins on the next. | |
-maximum-concurrent-test-device-destinations | number | If multiple device destinations are specified (and -disable-concurrent-destination-testing is not passed), only test on number devices at a time. For example, if four iOS devices are specified, but number is 2, the full test suite will run on each device, but only two devices will be testing at a given time. |
-maximum-concurrent-test-simulator-destinations | number | If multiple simulator destinations are specified (and -disable-concurrent-destination-testing is not passed), only test on number simulators at a time. For example, if four iOS simulators are specified, but number is 2, the full test suite will run on each simulator, but only two simulators will be testing at a given time. |
-parallel-testing-enabled | [YES / NO] | Overrides the per-target setting in the scheme for running tests in parallel. |
-parallel-testing-worker-count | number | Spawn exactly number test runners when executing tests in parallel. Overrides -maximum-parallel-testing-workers, if it is specified. |
-maximum-parallel-testing-workers | number | Limit the number of test runners that will be spawned when running tests in parallel to number. |
-dry-run, -n | Print the commands that would be executed, but do not execute them.很有意思的一个参数,就顺手复制了 |
Testing on Multiple Destinations//这个也会用的上的应该
When more than one destination is specified with the -destination option, xcodebuild tests on those destinations concurrently. In this mode, xcodebuild automatically chooses the number of devices and simulators that are used simultaneously. All enabled tests in the scheme or xctestrun file are run on each destination.
Exit Codes//可以手动退出
xcodebuild exits with codes defined by sysexits(3). It will exit with EX_OK on success. On failure, it will commonly exit with EX_USAGE if any options appear malformed, EX_NOINPUT if any input files cannot
be found, EX_IOERR if any files cannot be read or written, and EX_SOFTWARE if the commands given to xcodebuild fail. It may exit with other codes in less common scenarios.
开始写脚本
好,准备半天了。
FRAMEWORK_NAME='DemoDraven'
SCHEME_NAME='DemoDravenTests'
SIMULATOR='platform=iOS Simulator,name=iPhone 11 Pro,OS=13.3'
#进入到test.sh所在的目录,执行本文件
#Author:DravenLu
project_path=$(cd `dirname $0`; pwd)
TEST_PATH="${project_path}/TestScript"
echo ${TEST_PATH}
####最简单版执行所有的UT,编译文件,执行的结果什么的都是默认的路径
#-only-testing "${SCHEME_NAME}/GMDeviceTests/testExample" 执行某一个用例,执行全部去掉这个参数即可
#xcodebuild test -only-testing "${SCHEME_NAME}/GMDeviceTests/testExample" -project ${FRAMEWORK_NAME}.xcodeproj -scheme ${SCHEME_NAME} -destination 'platform=iOS Simulator,name=iPhone 11 Pro,OS=13.3'
####
####进阶版 编译 执行分开的,并且可以拿到测试结果
##如果输出目录存在,即移除该目录,再创建该目录。目的是为了清空输出目录。
DerivedDataPath="${TEST_PATH}/DerivedPath"
if [ -d ${DerivedDataPath} ]; then
rm -rf ${DerivedDataPath}
fi
mkdir -p ${DerivedDataPath}
ResultBundlePath="${TEST_PATH}/CoverageJSON"
if [ -d ${ResultBundlePath} ]; then
rm -rf ${ResultBundlePath}
fi
#这里不创建ResultBundlePath,不然 -resultBundlePath 这一行会报错,详情看-resultBundlePath参数的描述
##build-for-testing 在一个destination里只会创建一个xctestrun文件,所以-xctestrun参数的值,不用写死,写成变量
#xcodebuild build-for-testing -project ${FRAMEWORK_NAME}.xcodeproj -scheme ${SCHEME_NAME} -destination "${SIMULATOR}" -derivedDataPath "${DerivedDataPath}"
#
##xcodebuild test-without-building -xctestrun "${TEST_PATH}/DerivedPath/Build/Products/DemoDravenTests_iphonesimulator13.2-x86_64.xctestrun" -destination "${SIMULATOR}" -resultBundlePath /Users/Draven/Desktop/CheckReport
#XctestrunFilePath=`ls ${TEST_PATH}/DerivedPath/Build/Products/*xctestrun`
#
##上面注释的这一行优化成这样
#xcodebuild test-without-building -xctestrun "${XctestrunFilePath}" -destination "${SIMULATOR}" -resultBundlePath "${ResultBundlePath}"
##但是,我本地这样写不行,老是报找不到.xctestconfiguration(此处记为BUG1)
##Unable to load configuration data from specified path XXX.xctestconfiguration; error: The file “XXX.xctestconfiguration” couldn’t be opened because there is no such file.
####
####于是改成下面这样
xcodebuild test -only-testing "${SCHEME_NAME}/GMDeviceTests/testExample" -project ${FRAMEWORK_NAME}.xcodeproj -scheme ${SCHEME_NAME} -destination "${SIMULATOR}" -derivedDataPath "${DerivedDataPath}"
#去掉了resultBundlePath 参数,反正在derivedDataPath里面也能看到执行的结果
XctestResultFilePath="${DerivedDataPath}/Logs/Test/*xcresult"
XctestResultJSONPath="${ResultBundlePath}"
echo "🚀分析测试结果中🚀...."
echo ${XctestResultFilePath}
ruby "${TEST_PATH}/unitTestInfo.rb" --xcresult-path="${XctestResultFilePath}" --output-file="TestScript/test-result.txt"
xcrun xccov view --report --json ${XctestResultFilePath} > ${XctestResultJSONPath}
ruby "${TEST_PATH}/targetCoverage.rb" --cov-json-path="${XctestResultJSONPath}" --output-file="TestScript/test-coverage-result.html"
##参考JerryChu 的文章,感谢
##https://github.com/JerryChu/UnitTestParser
##测试结果覆盖率不满足直接exit,哈哈哈,大概就是这样
执行然后会打印这样的一段话,不管成功或者失败,都会有结果记录
Test session results, code coverage, and logs:
/Users/Draven/Desktop/CheckReport
参考
testing_with_xcode_automation
我只是个小小的搬运工
https://www.jianshu.com/p/4413d6879457
其实这里的例子很好用,哈哈
https://github.com/JerryChu/UnitTestParser
网友评论