Xcode 4:从命令行(xcodebuild)运行testing?
我已经在Xcode 4中创build了一个全新的iOS项目,并且包含了unit testing。 默认应用程序有2个目标,主应用程序和unit testing包。 使用“Product> Test”(Command-U)构build应用程序,构buildunit testing包,启动iOS模拟器并运行testing。 现在我想能够从命令行做同样的事情。 命令行工具(xcodebuild)没有“testing”动作,但似乎我应该能够直接构buildunit testing包目标,因为它取决于应用程序本身。 但是,运行:
xcodebuild -target TestAppTests -sdk iphonesimulator4.3 -configuration Debug build
给出以下消息:
/Developer/Platforms/iPhoneSimulator.platform/Developer/Tools/Tools/RunPlatformUnitTests:95: warning: Skipping tests; the iPhoneSimulator platform does not currently support application-hosted tests (TEST_HOST set).
这似乎是一个谎言,因为testing主机是设置为我的unit testing捆绑目标时,我从GUI运行Command-U。 我已经看到以前的post关于逻辑testing和应用程序testing之间的分离,但似乎Xcode 4消除了这种区别。 任何线索我怎么能从命令行运行我的testing?
重要的提示
使用Xcode 5.1(或许更早的Xcode) test
是一个有效的构build操作。
我们可以使用testing的构build操作和适当的-destination
选项来调用xcodebuild来replace下面的整个hack。 man xcodebuild
的更多信息。
下面的信息留给后人
我尝试黑客苹果的脚本来运行unit testing,如上所述
从命令行运行Xcode 4unit testing
和
Xcode4:从iOS中的命令行运行应用程序testing
以及整个networking上的许多类似的post。
但是,我遇到了这些解决scheme的问题。 我们的一些unit testing运行iOS Keychain和那些调用,当在黑客行动的环境中运行苹果的脚本,失败了一个错误( errSecNotAvailable
[-25291]为病态的好奇)。 结果,testing总是失败…在testing中一个不合需要的特点。
我尝试了许多基于我在networking上其他地方find的信息的解决scheme。 例如,其中一些解决scheme涉及尝试启动iOS模拟器的安全服务守护进程。 经过这些努力之后,我最好的select似乎是在模拟器的环境中充分利用iOS模拟器。
我所做的就是获取iOS模拟器启动工具ios-sim 。 这个命令行工具使用私有的Apple框架从命令行启动iOS应用程序。 然而,对我来说特别有用的是,它允许我将环境variables和命令行parameter passing到正在启动的应用程序。
虽然环境variables,我能够得到我的unit testing束注入到我的应用程序。 通过命令行参数,我可以传递所需的“-SenTest All”以使应用程序运行unit testing并退出。
我为我的unit testing包创build了一个Scheme(我称之为“CommandLineUnitTests”),并在构build部分中检查了“Run”动作,如上文中所述。
不过,我没有攻击苹果的脚本,而是用一个使用ios-sim启动应用程序的脚本replace了脚本,并设置了将unit testing包分别注入应用程序的环境。
我的脚本是用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
环境variables后,脚本在项目的源代码树中查找“启动程序”(iOS-sim可执行文件)。 然后,它根据Xcode在环境variables中传递的构build设置构build我的unit testing包的path。
接下来,我为正在运行的应用程序创build一组运行时环境variables,并注入unit testing包。 我在脚本中间的environment
哈希中设置了这些variables,然后使用一些ruby grunge将它们连接到ios-sim
应用程序的一系列命令行参数中。
在底部附近,从环境中抓取TEST_HOST
作为我想要启动的应用程序, system
命令实际执行ios-sim
传递应用程序,设置环境的命令参数以及参数-SenTest All
和testing包path到运行的应用程序。
这个scheme的优点是,它在模拟器环境中运行unit testing,就像我相信Xcode本身一样。 该scheme的缺点是它依靠外部工具来启动应用程序。 该外部工具使用私有的Apple框架,因此随后的OS发行版可能会变得很脆弱,但是它现在可行。
PS由于叙述的原因,我在这篇文章中使用了很多“我”,但是我的合伙人帕维尔(Pawel)曾经和我一起解决了这些问题。
我受到了约拿书的启发,find了一条办法:
基本上,你需要Xcode 4,你必须破解一个脚本,使其工作,但它确实。
关键是让Xcode 4运行你的iOStesting包,就好像它是一个MacOS X包 – 这是平台的问题,Xcode不想在命令行上运行应用程序testing。 有趣的,因为它似乎工作。
网站上还有一个示例项目。
你要找的是这个没有logging的参数(你也需要sdk和target)来从terminal运行你的OCUnittesting
xcodebuild -target MyTarget -sdk iphonesimulator TEST_AFTER_BUILD=YES
这是一个不完整的解决scheme,但我能够在自己的scheme中运行命令行版本的逻辑testing,并构build目标: http : //blog.carbonfive.com/2011/04/06/running-xcode-4-unit-tests-从最命令行/
xctool解决了这个问题: https : //github.com/facebook/xctool
我们在我们的持续集成服务器上使用它没有问题