Xcode 4:从命令行运行测试(xcodebuild)?

Ste*_*ner 47 xcode unit-testing xcodebuild ocunit xcode4

我在Xcode 4中创建了一个全新的iOS项目,并包含了单元测试.默认应用程序有2个目标,主应用程序和单元测试包.使用"产品>测试"(Command-U)构建应用程序,构建单元测试包,启动iOS模拟器并运行测试.现在,我希望能够从命令行执行相同的操作.命令行工具(xcodebuild)没有"测试"操作,但似乎我应该能够直接构建单元测试包目标,因为它取决于应用程序本身.但是,运行:

xcodebuild -target TestAppTests -sdk iphonesimulator4.3 -configuration Debug build
Run Code Online (Sandbox Code Playgroud)

给出以下消息:

/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).
Run Code Online (Sandbox Code Playgroud)

这似乎是一个谎言,因为当我从GUI运行Command-U时,为我的单元测试包目标设置了测试主机.我之前看过有关逻辑测试和应用程序测试之间分离的帖子,但似乎Xcode 4消除了这种区别.我是如何从命令行运行测试的?

Sco*_*son 48

重要的提示

使用Xcode 5.1(也许早期的Xcode)test是一个有效的构建操作.

我们能够使用test的构建操作和适当的-destination选项调用xcodebuild来替换下面的整个hack . man xcodebuild了解更多信息.

以下信息留给了后人


我试图破解Apple的脚本来运行单元测试

从命令行运行Xcode 4单元测试

Xcode4:从iOS中的命令行运行应用程序测试

网上有很多类似的帖子.

但是,我遇到了这些解决方案的问题.我们的一些单元测试运行了iOS Keychain,当在errSecNotAvailable恶意攻击Apple脚本的环境中运行时,这些调用失败并出现错误([-25291]对于病态的好奇).结果,测试总是失败......测试中的一个不良特征.

我根据我在网上其他地方找到的信息尝试了许多解决方案.例如,其中一些解决方案涉及尝试启动iOS模拟器的安全服务守护程序.在与这些人挣扎之后,我最好的选择似乎是在iOS模拟器中运行,充分利用了模拟器的环境.

我做了什么,然后得到了iOS模拟器启动工具ios-sim.此命令行工具使用私有Apple框架从命令行启动iOS应用程序.然而,对我来说特别有用的是,它允许我将环境变量和命令行参数传递给它正在启动的应用程序.

虽然环境变量,我能够将我的单元测试包注入我的应用程序.通过命令行参数,我可以传递"-SenTest All"以使应用程序运行单元测试并退出.

我为我的单元测试包创建了一个Scheme(我称之为"CommandLineUnitTests"),并检查了构建部分中的"运行"操作,如上面的帖子中所述.

不过,我没有攻击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
Run Code Online (Sandbox Code Playgroud)

从命令行运行它看起来像:

xcodebuild -sdk iphonesimulator -workspace iPhoneApp.xcworkspace/ -scheme "CommandLineUnitTests" clean build SL_RUN_UNIT_TESTS=YES
Run Code Online (Sandbox Code Playgroud)

在查找SL_RUN_UNIT_TESTS环境变量之后,脚本在项目的源树中找到"启动器"(iOS-sim可执行文件).然后,它根据Xcode在环境变量中传递的构建设置构建单元测试包的路径.

接下来,我为正在运行的应用程序创建了一组运行时环境变量,它注入了单元测试包.我environment在脚本中间的哈希中设置了这些变量,然后使用一些ruby grunge将它们连接到ios-sim应用程序的一系列命令行参数中.

在底部附近,我TEST_HOST从环境中抓取环境作为我想要启动的应用程序,system命令实际执行ios-sim传递应用程序,设置环境的命令参数,以及-SenTest All运行应用程序的参数和测试包路径.

这个方案的优点是它在模拟器环境中运行单元测试,就像我相信Xcode本身一样.该方案的缺点是它依赖于外部工具来启动应用程序.该外部工具使用私有Apple框架,因此随后的操作系统版本可能会很脆弱,但它目前仍然有效.

PS由于叙述的原因,我在这篇文章中经常使用"我",但很多功劳归功于我的犯罪伙伴Pawel,他和我一起解决了这些问题.

  • @ScottThompson你是如何使用Ruby脚本的?它必须替换/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Tools/RunPlatformUnitTests?它必须由它调用?我对它的位置有点迷茫. (6认同)
  • 你究竟在哪里使用那个红宝石代码? (3认同)
  • 这个答案应该被接受,也可以在XCode 4.5和Jenkins中使用!感谢分享.bigkm的答案只会运行逻辑单元测试,如果您构建工作区和方案而不是目标,则无法应用. (2认同)

mak*_*dad 9

我受到乔纳的帖子的启发,并找到了一种方法:

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

基本上,你需要Xcode 4,你必须破解脚本才能使它工作,但确实如此.

关键点在于说服Xcode 4运行你的iOS测试包,好像它是一个MacOS X包 - 这是平台的一个问题,Xcode不想在命令行上运行开箱即用的应用程序测试.有趣,因为它似乎工作.

网站上还有一个示例项目.


big*_*gkm 8

您正在寻找的是这个未记录的参数(您确实需要sdk和目标)来从终端运行您的OCUnit测试

xcodebuild  -target MyTarget -sdk iphonesimulator   TEST_AFTER_BUILD=YES
Run Code Online (Sandbox Code Playgroud)

  • 这只会运行逻辑单元测试,如果您构建工作空间而不是目标,则可能会出现问题.在我的项目中,我有工作区来处理依赖项,所以我不可能切换到构建目标. (3认同)
  • 请注意,这不是一个未记录的参数,而是您正在设置的环境变量. (2认同)

Jon*_*nah 5

这是一个不完整的解决方案,但我能够在自己的方案中运行逻辑测试的命令行构建并构建目标:http://blog.carbonfive.com/2011/04/06/running-xcode-4-unit-tests-从最命令行/