web-dev-qa-db-fra.com

Xcode 4: exécuter des tests à partir de la ligne de commande (xcodebuild)?

J'ai créé un tout nouveau projet iOS dans Xcode 4 et inclus des tests unitaires. L'application par défaut a 2 cibles, l'application principale et l'ensemble de tests unitaires. L'utilisation de "Product> Test" (Command-U) crée l'application, crée le bundle de tests unitaires, lance le simulateur iOS et exécute les tests. Maintenant, j'aimerais pouvoir faire la même chose depuis la ligne de commande. L'outil de ligne de commande (xcodebuild) n'a pas d'action "test", mais il semble que je devrais pouvoir construire directement la cible du bundle de test unitaire, car cela dépend de l'application elle-même. Cependant, en cours d'exécution:

xcodebuild -target TestAppTests -sdk iphonesimulator4.3 -configuration Debug build

donne le message suivant:

/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).

Cela semble être un mensonge, car l'hôte de test est défini pour ma cible de bundle de tests unitaires lorsque j'exécute Command-U à partir de l'interface graphique. J'ai vu des articles précédents sur la séparation entre les tests logiques et les tests d'application, mais il semble que Xcode 4 supprime cette distinction. Avez-vous une idée de la façon dont je peux exécuter mes tests à partir de la ligne de commande?

47
Steven Wisener

Note importante

Avec Xcode 5.1 (peut-être aussi le Xcode antérieur) test est une action de build valide.

Nous avons pu remplacer l'intégralité du hack ci-dessous par un appel à xcodebuild en utilisant l'action de génération de test et avec -destination options. man xcodebuild pour plus d'informations.

Les informations ci-dessous sont laissées ici pour la postérité


J'ai essayé de pirater les scripts d'Apple pour exécuter des tests unitaires comme mentionné dans

Exécution de tests unitaires Xcode 4 à partir de la ligne de commande

et

Xcode4: Exécution de tests d'application à partir de la ligne de commande dans iOS

et de nombreuses publications similaires sur le Web.

Cependant, j'ai rencontré un problème avec ces solutions. Certains de nos tests unitaires ont exercé le trousseau iOS et ces appels, lorsqu'ils s'exécutaient dans l'environnement provenant du piratage des scripts d'Apple, ont échoué avec une erreur (errSecNotAvailable [- 25291] pour les curieux morbides). En conséquence, les tests ont toujours échoué ... une caractéristique indésirable dans un test.

J'ai essayé un certain nombre de solutions basées sur des informations que j'ai trouvées ailleurs sur le Web. Par exemple, certaines de ces solutions impliquaient d'essayer de lancer le démon des services de sécurité du simulateur iOS. Après avoir lutté avec ceux-ci, mon meilleur pari semblait être de fonctionner dans le simulateur iOS avec tous les avantages de l'environnement du simulateur.

Ce que j'ai fait, c'est mettre la main sur l'outil de lancement du simulateur iOS ios-sim . Cet outil de ligne de commande utilise des cadres privés Apple pour lancer une application iOS à partir de la ligne de commande. Cependant, il m'a été particulièrement utile de pouvoir passer à la fois les variables d'environnement et la ligne de commande. Arguments à l'application qu'elle lance.

Bien que les variables d'environnement, j'ai pu obtenir mon bundle de tests unitaires injecté dans mon application. Grâce aux arguments de la ligne de commande, je peux passer le "-SenTest All" nécessaire pour que l'application exécute les tests unitaires et quitte.

J'ai créé un schéma (que j'ai appelé "CommandLineUnitTests") pour mon lot de tests unitaires et vérifié l'action "Exécuter" dans la section de construction comme décrit dans les articles ci-dessus.

Plutôt que de pirater les scripts d'Apple, j'ai remplacé le script par un script qui lance l'application à l'aide d'ios-sim et configure l'environnement pour injecter mon lot de tests unitaires dans l'application séparément.

Mon script est écrit en Ruby qui m'est plus familier que le script BASH. Voici ce script:

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

L'exécution à partir de la ligne de commande ressemble à ceci:

xcodebuild -sdk iphonesimulator -workspace iPhoneApp.xcworkspace/ -scheme "CommandLineUnitTests" clean build SL_RUN_UNIT_TESTS=YES

Après avoir recherché le SL_RUN_UNIT_TESTS variable d'environnement, le script trouve le "lanceur" (l'exécutable iOS-sim) dans l'arborescence source du projet. Il construit ensuite le chemin vers mon bundle de tests unitaires en fonction des paramètres de construction que Xcode passe dans les variables d'environnement.

Ensuite, je crée l'ensemble des variables d'environnement d'exécution pour mon application en cours d'exécution qui injectent le bundle de tests unitaires. J'ai configuré ces variables dans le hachage environment au milieu du script, puis j'utilise certains Ruby grunge pour les joindre en une série d'arguments de ligne de commande pour le ios-sim application.

Près du bas, j'attrape le TEST_Host depuis l'environnement comme l'application que je veux lancer et la commande system exécute en fait ios-sim en passant l'application, les arguments de commande pour configurer l'environnement et les arguments -SenTest All et le chemin du bundle de test vers l'application en cours d'exécution.

L'avantage de ce schéma est qu'il exécute les tests unitaires dans l'environnement du simulateur comme je pense que Xcode lui-même le fait. L'inconvénient du schéma est qu'il s'appuie sur un outil externe pour lancer l'application. Cet outil externe utilise des frameworks privés Apple, il peut donc être fragile avec les versions ultérieures du système d'exploitation, mais il fonctionne pour le moment.

P.S. J'ai beaucoup utilisé "je" dans ce post pour des raisons narratives, mais une grande partie du mérite revient à mon partenaire dans le crime, Pawel, qui a résolu ces problèmes avec moi.

48
Scott Thompson

J'ai été inspiré par le post de Jonah et j'ai trouvé un moyen de le faire:

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

Fondamentalement, vous avez besoin de Xcode 4 et vous devez pirater un script pour le faire fonctionner, mais c'est le cas.

Le point clé est de convaincre Xcode 4 d'exécuter votre bundle de test iOS comme s'il s'agissait d'un bundle MacOS X - c'est un problème avec la plate-forme, Xcode ne veut pas exécuter des tests d'application hors de la boîte sur la ligne de commande. Drôle, car cela semble fonctionner.

Il y a aussi un exemple de projet sur le site.

9
makdad

ce que vous recherchez est cet argument non documenté (vous avez également besoin de sdk et de cible) pour exécuter vos tests OCUnit à partir du terminal

xcodebuild  -target MyTarget -sdk iphonesimulator   TEST_AFTER_BUILD=YES
8
bigkm

C'est une solution incomplète mais j'ai pu exécuter des builds de ligne de commande de tests logiques dans leur propre schéma et construire la cible: http://blog.carbonfive.com/2011/04/06/running-xcode-4- tests unitaires depuis la ligne de commande /

5
Jonah

xctool résout ce problème: https://github.com/facebook/xctool

nous l'utilisons sur notre serveur d'intégration continue sans problème

3
skrusche