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了一条办法:

http://longweekendmobile.com/2011/04/17/xcode4-running-application-tests-from-the-command-line-in-ios/

基本上,你需要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

我们在我们的持续集成服务器上使用它没有问题