47 votes

Xcode 4 : Exécuter les tests depuis 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 le bundle de tests unitaires. L'utilisation de "Produit > Test" (Commande-U) construit l'application, construit le paquet de tests unitaires, lance le simulateur iOS et exécute les tests. J'aimerais maintenant pouvoir faire la même chose à partir de 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 tests unitaires, puisqu'elle dépend de l'application elle-même. Cependant, l'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, puisque Test Host est défini pour la cible de mon bundle de tests unitaires lorsque j'exécute Command-U depuis 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 ?

48voto

Scott Thompson Points 10516

Note importante

Avec Xcode 5.1 (peut-être aussi les Xcode antérieurs) test est une action de construction valide.

Nous avons pu remplacer l'ensemble du hack ci-dessous par un appel à xcodebuild en utilisant l'action de construction de test et avec les paramètres appropriés de -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 les tests unitaires comme mentionné dans

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

et

Xcode4 : Exécution des 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 font appel au trousseau d'iOS et ces appels, lorsqu'ils sont exécutés dans l'environnement qui résulte du piratage des scripts d'Apple, échouent avec une erreur ( errSecNotAvailable [-25291] pour les curieux morbides). En conséquence, les tests échouaient toujours... 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. Certaines de ces solutions impliquaient d'essayer de lancer le démon des services de sécurité du simulateur iOS, par exemple. Après m'être débattu avec ces solutions, il m'a semblé que ma meilleure option était de fonctionner dans le simulateur iOS en profitant pleinement de l'environnement du simulateur.

Ce que j'ai fait, alors, c'est mettre la main sur l'outil de lancement du simulateur iOS. ios-sim . Cet outil en ligne de commande utilise les frameworks privés d'Apple pour lancer une application iOS à partir de la ligne de commande. Ce qui m'a particulièrement intéressé, c'est qu'il me permet de passer à la fois des variables d'environnement et des arguments de ligne de commande à l'application qu'il lance.

Grâce aux variables d'environnement, j'ai pu injecter mon paquet de tests unitaires 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 paquet de tests unitaires et j'ai coché l'action "Run" dans la section build comme décrit dans les posts ci-dessus.

Mais plutôt que de pirater les scripts d'Apple, j'ai remplacé le script par un script qui lance l'application en utilisant ios-sim et met en place l'environnement pour injecter mon bundle 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écuter à partir de la ligne de commande ressemble à ça :

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

Après avoir cherché le SL_RUN_UNIT_TESTS le script trouve le "launcher" (l'exécutable iOS-sim) dans l'arbre source du projet. Il construit ensuite le chemin vers mon Bundle de test unitaire en fonction des paramètres de construction que Xcode transmet dans les variables d'environnement.

Ensuite, je crée l'ensemble des variables d'environnement d'exécution de mon application en cours d'exécution qui injectent le paquet de tests unitaires. Je configure ces variables dans le fichier environment au milieu du script, puis utiliser un peu de ruby grunge pour les joindre en une série d'arguments de ligne de commande pour la commande ios-sim application.

Vers le bas, je prends le TEST_HOST de l'environnement comme l'application que je veux lancer et la system exécute réellement la commande ios-sim passant l'application, les arguments de la commande pour configurer l'environnement, et les arguments -SenTest All et le chemin du paquet de test de l'application en cours d'exécution.

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

P.S. J'ai beaucoup utilisé le "je" dans ce billet pour des raisons narratives, mais le mérite en revient en grande partie à mon partenaire de crime, Pawel, qui a travaillé sur ces problèmes avec moi.

9voto

makdad Points 4670

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/

En gros, vous avez besoin de Xcode 4 et vous devez pirater un script pour que ça marche, mais ça marche.

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 plateforme, Xcode ne veut pas exécuter les tests d'application en ligne de commande. C'est drôle, car cela semble fonctionner.

Il y a également un exemple de projet sur le site.

8voto

bigkm Points 984

Ce que vous recherchez est cet argument non documenté (vous avez également besoin de sdk et target) pour exécuter vos tests OCUnit depuis le terminal.

xcodebuild  -target MyTarget -sdk iphonesimulator   TEST_AFTER_BUILD=YES

5voto

Jonah Points 11568

C'est une solution incomplète mais j'ai pu exécuter des constructions en ligne de commande de tests logiques dans leur propre schéma et cible de construction : http://blog.carbonfive.com/2011/04/06/running-xcode-4-unit-tests-from-the-command-line/

3voto

skrusche Points 60

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

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X