web-dev-qa-db-fra.com

Xcode: macros de préprocesseur TEST vs DEBUG

Lors de la création d'un nouveau projet avec des tests unitaires, Xcode définit la configuration de la construction sur Debug pour le schéma de test (identique pour le schéma d'exécution).

Devrais-je différencier les modèles Exécuter (Command-R) et Test (Command-U)?

Par exemple, devrais-je créer une nouvelle configuration de construction appelée Test, y ajouter une macro de préprocesseur TEST = 1 et l'utiliser comme configuration de construction pour le schéma de test? Ou, devrais-je simplement garder Run & Test comme Debug?

Je viens de Ruby/Rails, où vous avez généralement des environnements de test, de développement et de production. Il me semble que Debug est comme le développement et que Release est comme la production, mais il nous manque un test, c'est pourquoi je pense qu'il pourrait être judicieux d'ajouter Test.

Commentaires? Des avis? Suggestions?

Je demande spécifiquement ceci parce que je veux compiler quelque chose pour Test avec:

#ifdef TEST
// Do something when I test.
#endif

Je ne pense pas que ce soit important si je compile aussi ceci pour Debug. Donc, je pourrais vraiment faire:

#ifdef DEBUG
// Do something when I run or test.
#endif

Mais je n'ai vraiment l'intention que de le faire pour des tests pour le moment. C'est pourquoi je pense que je devrais faire la distinction entre debug et test, mais je me demande pourquoi Xcode ne le fait pas pour vous par défaut? Apple pense-t-il que vous ne devriez pas les différencier?

32
ma11hew28

Au lieu de créer une configuration de construction de test, je:

  1. créé un fichier Tests-Prefix.pch:

    #define TEST 1
    #import <SenTestingKit/SenTestingKit.h>
    #import "CocoaPlant-Prefix.pch"
    
  2. a entré son chemin dans le champ En-tête du préfixe des paramètres de construction de la cible de tests.

  3. ajouté le code suivant en haut d'un fichier que j'ai créé et appelé MyAppDefines.h, importé dans MyApp-Prefix.pch:

    #ifdef TEST
    #define TEST_CLASS NSClassFromString(@"AppDelegateTests") // any test class
    #define BUNDLE [NSBundle bundleForClass:TEST_CLASS]
    #define APP_NAME @"Tests"
    #else
    #define BUNDLE [NSBundle mainBundle]
    #define APP_NAME [[BUNDLE infoDictionary] objectForKey:(NSString *)kCFBundleNameKey]
    #endif
    

Cela me permet d'utiliser BUNDLE partout où je veux dire [NSBundle mainBundle] et aussi de le faire fonctionner lorsque j'exécute des tests.

L'importation de SenTestingKit dans Tests-Prefix.pch accélère également la compilation du framework SenTestingKit et me permet de laisser de côté #import <SenTestingKit/SenTestingKit.h> du haut de tous les fichiers de test.

24
ma11hew28

Les macros de préprocesseur ne fonctionneront pas, vous devez vérifier l'environnement au moment de l'exécution.

static BOOL isRunningTests(void)
{
    NSDictionary* environment = [[NSProcessInfo processInfo] environment];
    return (environment[@"XCInjectBundleInto"] != nil);
}

(Mise à jour pour Xcode 7.3)

27
Robert

Vous pourriez envisager d'ajouter une nouvelle configuration de construction.

Dans xcode 4, cliquez sur votre projet dans le navigateur de gauche.

Dans la fenêtre principale, cliquez sur votre projet, puis sélectionnez l'onglet "Info".

Cliquez sur le bouton "+" pour ajouter une nouvelle configuration (vous pouvez appeler le "test" si vous le souhaitez ").

Maintenant, cliquez sur votre cible et allez dans l'onglet des paramètres de construction.

Recherche de "macros de préprocesseur"

Ici, vous pouvez ajouter des macros de préprocesseur pour votre nouvelle configuration de construction.

Double-cliquez simplement sur votre nouvelle configuration "test" et ajoutez TESTING = 1.

Enfin, éditez votre schéma de construction. Sélectionnez les options de test pour votre schéma. Il devrait y avoir un menu déroulant "Build Configuration". Sélectionnez votre configuration "test".

27
David

J'ai décidé d'ajouter une vérification d'une variable d'environnement dans le code lui-même, au lieu d'utiliser la suggestion de isRunningTests () suggérée par Robert.

  1. Editez le schéma actuel (Product/Scheme/Edit Scheme) ou Commande + <
  2. Cliquez sur la configuration de test
  3. Cliquez sur Arguments Décochez la case "Utiliser les arguments et les variables d'environnement de l'action Exécuter."
  4. Développez la section Variable d'environnement et ajoutez la variable TESTING avec la valeur YES
  5. Ajoutez ceci à votre code quelque part et appelez chaque fois que vous avez besoin de:
 + (BOOL) isTesting
    {
        NSDictionary* environment = [[NSProcessInfo processInfo] environment];
        return [environment objectForKey:@"TESTING"] != nil;
    }

L'écran devrait ressembler à ceci lorsque vous avez terminé.

The screen should look like this

Le code ci-dessus trouvera la variable d'environnement TESTING lors de l'exécution en mode test ou en mode application. Ce code va dans votre application, pas dans les fichiers de test unitaires. Vous pouvez utiliser

#ifdef DEBUG
...
#endif

Pour empêcher le code d'être exécuté en production.

16
focused4success

La réponse de Robert dans Swift 3.0:

func isRunningTests() -> Bool {
    let environment = ProcessInfo().environment
    return (environment["XCInjectBundleInto"] != nil);
}
4
Houman

J'ai testé si longtemps, j'ai trouvé un résultat:

Non seulement vous ajoutez la macro pré-processeur à votre cible de test unitaire (vous pouvez utiliser plusieurs méthodes en utilisant des variables pour le test unitaire uniquement , Et suivez les méthodes @MattDiPasquale),

mais vous devez également ajouter le fichier de conformité à la condition dans votre cible de test . Nous devons recomplier ce fichier, car vous disposez d'une nouvelle macro de préprocesseur pour ce fichier, macro n'a pas défini.

J'espère que cela vous aidera.

2
regrecall

Si vous créez une configuration de construction Test, puis définissez la propriété "Autres drapeaux Swift" de votre cible sur "-DTEST", elle définira une macro TEST qui fonctionnera dans votre code Swift. Assurez-vous de le définir dans les paramètres de construction de votre cible d'application afin de pouvoir l'utiliser dans le code Swift de votre application.

 Other Swift Flags setting for DEBUG and TEST

Ensuite, avec cet ensemble, vous pouvez tester votre code comme suit:

func testMacro() {
   #if !TEST 
       // skipping over this block of code for unit tests
   #endif
}
1
ucangetit

Sur iOS, [UIApplication sharedApplication] renverra nil lorsqu'un test unitaire est en cours d'exécution. 

0
Frank Schmitt

Examinez les variables d'environnement pour voir si les tests unitaires sont en cours d'exécution. Semblable à la réponse de Robert, mais je ne vérifie qu'une fois le rendement.

+ (BOOL)isRunningTests {
   static BOOL runningTests;
   static dispatch_once_t onceToken;

   // Only check once
   dispatch_once(&onceToken, ^{
      NSDictionary* environment = [[NSProcessInfo processInfo] environment];
      NSString* injectBundle = environment[@"XCInjectBundle"];
      NSString* pathExtension = [injectBundle pathExtension];
      runningTests = ([pathExtension isEqualToString:@"octest"] ||
                      [pathExtension isEqualToString:@"xctest"]);
   });
   return runningTests;
}
0
kev

Version modifiée de la réponse de Kev qui fonctionne pour moi sur Xcode 8.3.2

+(BOOL)isUnitTest {

    static BOOL runningTests;
    static dispatch_once_t onceToken;

    // Only check once
    dispatch_once(&onceToken, ^{
        NSDictionary* environment = [[NSProcessInfo processInfo] environment];
        if (environment[@"XCTestConfigurationFilePath"] != nil && ((NSString *)environment[@"XCTestConfigurationFilePath"]).length > 0) {
            runningTests = true;
        } else {
            runningTests = false;
        }
    });
    return runningTests;
}
0
Fresh One