重要的提示
使用 Xcode 5.1(也许早期的 Xcode 也是如此)test
是一个有效的构建操作。
我们能够使用 test 的构建操作和适当的-destination
选项调用 xcodebuild 来替换下面的整个 hack。 man xcodebuild
了解更多信息。
以下信息留作后人
我尝试破解 Apple 的脚本来运行单元测试,如
从命令行运行 Xcode 4 单元测试
和
Xcode4:在 iOS 中从命令行运行应用程序测试
以及网络上许多类似的帖子。
但是,我遇到了这些解决方案的问题。我们的一些单元测试执行了 iOS 钥匙串,当在来自黑客 Apple 脚本的环境中运行时,这些调用因错误而失败(errSecNotAvailable
[-25291] 表示病态的好奇)。结果,测试总是失败......测试中的一个不受欢迎的功能。
根据我在网上其他地方找到的信息,我尝试了许多解决方案。例如,其中一些解决方案涉及尝试启动 iOS 模拟器的安全服务守护进程。在与这些斗争之后,我最好的选择似乎是在 iOS 模拟器中运行,充分利用模拟器环境。
我所做的就是使用 iOS Simulator 启动工具ios-sim。此命令行工具使用私有 Apple 框架从命令行启动 iOS 应用程序。然而,对我来说特别有用的是它允许我将环境变量和命令行参数传递给它正在启动的应用程序。
通过环境变量,我能够将单元测试包注入到我的应用程序中。通过命令行参数,我可以传递让应用程序运行单元测试并退出所需的“-SenTest All”。
我为我的单元测试包创建了一个方案(我称之为“CommandLineUnitTests”)并检查了构建部分中的“运行”操作,如上面的帖子中所述。
不过,我没有破解 Apple 的脚本,而是将脚本替换为使用 ios-sim 启动应用程序并设置环境以将我的单元测试包单独注入应用程序的脚本。
我的脚本是用比 BASH 脚本更熟悉的 Ruby 编写的。这是那个脚本:
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 grunge 将它们加入到应用程序的一系列命令行参数中ios-sim
。
在底部附近,我TEST_HOST
从环境中获取了我想要启动的应用程序,并且system
命令实际上执行ios-sim
传递应用程序、设置环境的命令参数-SenTest All
以及正在运行的应用程序的参数和测试包路径。
这种方案的优点是它在模拟器环境中运行单元测试,就像我相信 Xcode 本身一样。该方案的缺点是它依赖于外部工具来启动应用程序。该外部工具使用私有的 Apple 框架,因此在随后的操作系统版本中它可能很脆弱,但目前它可以工作。
PS 出于叙述原因,我在这篇文章中经常使用“我”,但很多功劳归功于我的犯罪伙伴 Pawel,他与我一起解决了这些问题。