web-dev-qa-db-fra.com

Commande d'unité de test à l'aide de XCTest dans Xcode 6

Je voudrais savoir s'il existe un moyen de dire à Xcode d'exécuter des tests unitaires dans un ordre spécifié. Je veux dire pas dans un même fichier de classe XCTestCase, mais entre tout le fichier de classe.

enter image description here

Par exemple, je veux exécuter SitchozrSDKSessionTest avant d'exécuter SitchozrSDKMessageTest.

J'ai regardé quelques threads sur la pile ou sur la documentation Apple et je n'ai rien trouvé d'utile.

Merci de votre aide.

32
BoilingLime

Tout est trié par ordre alphabétique (classes et méthodes). Ainsi, lorsque vous avez besoin de tests en dernier lieu, changez simplement le nom de la classe ou de la méthode (par exemple (désagréable) en préfixant 'z_').

Donc ... Vous avez des noms de classe:

MyAppTest1
  -testMethodA
  -testMethodB
MyAppTest2
  -testMethodC
  -testMethodD

et ils courent dans cet ordre. Si vous devez exécuter MyAppTest1 en deuxième, renommez-le simplement pour que son nom apparaisse alphabétiquement après MyAppTest2 (z_MyAppTest1) et il s'exécutera (idem pour la méthode):

MyAppTest2
  -a_testMethodD
  -testMethodC
z_MyAppTest1
  -testMethodA
  -testMethodB

Veuillez également prendre le nom comme exemple :)

27
JakubKnejzlik

Il est vrai qu'actuellement (à partir de Xcode 7), les méthodes XCTestCase sont exécutées dans l'ordre alphabétique, vous pouvez donc forcer une commande pour elles en les nommant intelligemment. Cependant, il s'agit d'un détail d'implémentation qui semble pouvoir changer.

Une manière (espérons-le) moins fragile de le faire est de remplacer +[XCTestCase testInvocations] et renvoyez vos propres objets NSInvocation dans l'ordre dans lequel vous souhaitez exécuter les tests.

Quelque chose comme:

+ (NSArray *)testInvocations
{
    NSArray *selectorStrings = @[@"testFirstThing",
                                 @"testSecondThing",
                                 @"testAnotherThing",
                                 @"testLastThing"];

    NSMutableArray *result = [NSMutableArray array];
    for (NSString *selectorString in selectorStrings) {
        SEL selector = NSSelectorFromString(selectorString);
        NSMethodSignature *methodSignature = [self instanceMethodSignatureForSelector:selector];
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
        invocation.selector = selector;
        [result addObject:invocation];
    }
    return result;
}

Bien sûr, l'inconvénient ici est que vous devez ajouter manuellement chaque méthode de test à celle-ci au lieu de les prendre automatiquement. Il existe plusieurs façons d'améliorer cette situation. Si vous avez seulement besoin de commander certaines de vos méthodes de test, pas toutes, dans votre remplacement de +testInvocations, vous pouvez appeler super, filtrer les méthodes que vous avez commandées manuellement, puis clouer le reste à la fin du tableau que vous retournez. Si vous devez commander toutes les méthodes de test, vous pouvez toujours obtenir le résultat de l'appel à super et vérifier que toutes les méthodes récupérées automatiquement sont couvertes par votre résultat ordonné créé manuellement. Sinon, vous pouvez affirmer, provoquant un échec si vous avez oublié d'ajouter des méthodes.

Je laisse de côté la discussion de savoir s'il est "correct" d'écrire des tests qui doivent s'exécuter dans un certain ordre. Je pense qu'il existe de rares scénarios où cela a du sens, mais d'autres peuvent être en désaccord.

15
Andrew Madsen

son ordre par nom de fonction correspond à l'ordre des lettres, peu importe comment vous le commandez dans votre code. par exemple.:

-(void)testCFun(){};
-(void)testB2Fun(){};
-(void)testB1Fun(){};

l'ordre d'exécution réel est:

  1. testB1Fun appelé
  2. testB2Fun appelé
  3. testCFun appelé
7
Jixian Wang

En plus de la réponse de andrew-madsen :
J'ai créé une méthode de classe 'smart' testInvocations qui recherche les sélecteurs commençant par "test" et les trie par ordre alphabétique.
Vous n'avez donc pas à gérer séparément un NSArray de noms de sélecteur.

#import <objc/runtime.h>

+ (NSArray <NSInvocation *> *)testInvocations
{
    // Get the selectors of this class
    unsigned int mc = 0;
    Method *mlist = class_copyMethodList(self.class, &mc);
    NSMutableArray *selectorNames = [NSMutableArray array];
    for (int i = 0; i < mc; i++) {
        NSString *name = [NSString stringWithFormat:@"%s", sel_getName(method_getName(mlist[i]))];
        if (name.length > 4
            && [[name substringToIndex:4] isEqualToString:@"test"]) {
            [selectorNames addObject:name];
        }
    }

    // Sort them alphabetically
    [selectorNames sortUsingComparator:^NSComparisonResult(NSString * _Nonnull sel1, NSString * _Nonnull sel2) {
        return [sel1 compare:sel2];
    }];

    // Build the NSArray with NSInvocations
    NSMutableArray *result = [NSMutableArray array];
    for (NSString *selectorString in selectorNames) {
        SEL selector = NSSelectorFromString(selectorString);
        NSMethodSignature *methodSignature = [self instanceMethodSignatureForSelector:selector];
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
        invocation.selector = selector;
        [result addObject:invocation];
    }
    return result;
}

Note de bas de page: Il est considéré comme une mauvaise pratique de faire dépendre les tests unitaires les uns des autres

6
basvk

Pour votre exemple, vous pouvez simplement renommer les fichiers de tests sur votre projet comme ceci:

SitchozrSDKSessionTest -> t001_SitchozrSDKSessionTest
SitchozrSDKMessageTest -> t002_SitchozrSDKMessageTest

Xcode traite les fichiers par ordre alphabétique.

3
ant_one

Depuis Xcode 7, les sous-classes XCTestCase sont classées par ordre alphabétique. Si vous souhaitez vous assurer que les méthodes de test elles-mêmes sont également exécutées dans l'ordre alphabétique, vous devez remplacer la méthode de classe testInvocations et renvoyer les appels triés par sélecteur.

@interface MyTestCase : XCTestCase
@end

@implementation MyTestCase

+ (NSArray<NSInvocation *> *) testInvocations
{
    return [[super testInvocations] sortedArrayUsingComparator:^NSComparisonResult(NSInvocation *invocation1, NSInvocation *invocation2) {
        return [NSStringFromSelector(invocation1.selector) compare:NSStringFromSelector(invocation2.selector)];
    }];
}

- (void) test_01
{
}

- (void) test_02
{
}

@end
2
0xced

Le PO n'a pas mentionné si l'IC est disponible ou si une réponse en ligne de commande serait suffisante. Dans ces cas, j'ai apprécié l'utilisation de xctool [1]. Il a une syntaxe pour exécuter des tests jusqu'à une seule méthode de test:

path/to/xctool.sh \
  -workspace YourWorkspace.xcworkspace \
  -scheme YourScheme \
  test -only SomeTestTarget:SomeTestClass/testSomeMethod

Je vais le faire pour nous assurer que nous testons d'abord les éléments qui nous semblent les plus faciles.

1. [] facebook/xctool: Un remplacement pour xcodebuild d'Apple qui facilite la construction et le test des applications iOS ou OSX. ; ; https://github.com/facebook/xctool

1
AnneTheAgile