重要提示
使用Xcode 5.1(或许早期的Xcode也是)test
是一个有效的构建操作。
我们能够通过调用带有适当的-destination
选项的xcodebuild的构建操作来替换下面的整个hack。更多信息请参见man xcodebuild
。
以下信息留在此处供后人参考
我试图黑客攻击Apple的脚本以运行单元测试,如下所述
从命令行中运行Xcode 4单元测试
和
Xcode4:在iOS中从命令行运行应用程序测试
以及互联网上的类似帖子不计其数。
但是,我在这些解决方案中遇到了一个问题。我们的一些单元测试使用了iOS Keychain,当在来自黑客攻击Apple脚本的环境中运行那些调用时,会出现错误(对于好奇心者,是errSecNotAvailable
[-25291])。因此,测试始终失败......这是一个测试中不希望出现的特性。
我尝试了许多基于我在互联网上找到的信息的解决方案。其中一些解决方案涉及尝试启动iOS模拟器的安全服务守护程序,例如。在苦苦挣扎后,我的最佳选择似乎是在iOS模拟器中运行,并充分利用模拟器的环境。
然后我获取了iOS模拟器启动工具ios-sim。这个命令行工具使用专有的Apple框架从命令行启动iOS应用程序。对我特别有用的是,它允许我将环境变量和命令行参数传递给它正在启动的应用程序。
通过环境变量,我能够将我的单元测试捆绑包注入到我的应用程序中。通过命令行参数,我可以传递"-SenTest All",以使应用程序运行单元测试并退出。
我为我的单元测试捆绑包创建了一个方案(我称之为"CommandLineUnitTests"),并在构建部分中勾选了"Run"操作,如上述帖子中所述。
不过,我并没有黑客攻击Apple的脚本,而是用一个脚本替换了该脚本,该脚本使用ios-sim启动应用程序,并设置环境以单独将我的单元测试捆绑包注入应用程序中。
我的脚本是用Ruby编写的,这比BASH脚本更熟悉。以下是那个脚本:
if ENV['SL_RUN_UNIT_TESTS'] then
launcher_path = File.join(ENV['SRCROOT'], "Scripts", "ios-sim")
test_bundle_path= File.join(ENV['BUILT_PRODUCTS_DIR'], "#{ENV['PRODUCT_NAME']}.#{ENV['WRAPPER_EXTENSION']}")
environment = {
'DYLD_INSERT_LIBRARIES' => "/../../Library/PrivateFrameworks/IDEBundleInjection.framework/IDEBundleInjection",
'XCInjectBundle' => test_bundle_path,
'XCInjectBundleInto' => ENV["TEST_HOST"]
}
environment_args = environment.collect { |key, value| "--setenv #{key}=\"#{value}\""}.join(" ")
app_test_host = File.dirname(ENV["TEST_HOST"])
system("#{launcher_path} launch \"#{app_test_host}\" #{environment_args} --args -SenTest All #{test_bundle_path}")
else
puts "SL_RUN_UNIT_TESTS not set - Did not run unit tests!"
end
从命令行运行的样子如下:
xcodebuild -sdk iphonesimulator -workspace iPhoneApp.xcworkspace/ -scheme "CommandLineUnitTests" clean build SL_RUN_UNIT_TESTS=YES
在查找SL_RUN_UNIT_TESTS
环境变量后,脚本在项目源树中找到了“启动器”(iOS-sim可执行文件)。然后,它基于Xcode通过环境变量传递的构建设置构建了我的单元测试捆绑包的路径。
接下来,我为运行应用程序创建了一组运行时环境变量,以注入单元测试捆绑包。我在脚本中间的environment
哈希中设置了这些变量,然后使用一些ruby技巧将它们连接成一系列命令行参数,以供ios-sim
应用程序使用。
接近底部,我从环境中获取了TEST_HOST
作为我要启动的应用程序,system
命令实际上执行了ios-sim
,传递应用程序、设置环境的命令参数和参数-SenTest All
以及测试捆绑包路径到正在运行的应用程序。
这种方案的优点是它在模拟器环境中运行单元测试,与我认为Xcode本身的方式非常相似。该方案的缺点是它依赖于外部工具来启动应用程序。该外部工具使用私有的Apple框架,因此可能会因为随后的操作系统发布而变得脆弱,但目前它可以工作。
附言:我在本帖中经常使用“我”这个词进行叙述,但很多功劳归于我的伙伴Pawel,他和我一起解决了这些问题。