37 votes

Erreur XCTAssertEqual : ("3") n'est pas égal à ("3")

NSMutableArray *arr = [NSMutableArray array];
[arr addObject:@"1"];
[arr addObject:@"2"];
[arr addObject:@"3"];

// This statement is fine.
XCTAssertTrue(arr.count == 3, @"Wrong array size.");

// This assertion fails with an error: ((arr.count) equal to (3)) failed: ("3") is not equal to ("3")
XCTAssertEqual(arr.count, 3, @"Wrong array size.");

Qu'est-ce que je ne comprends pas dans XCTAssertEqual ? Pourquoi la dernière assertion échoue-t-elle ?

47voto

ephemera Points 2690

J'ai également eu pas mal de problèmes avec les tests de Xcode 5. Il semble encore assez bogué avec certains comportements étranges - cependant, j'ai trouvé la raison définitive pour laquelle votre problème particulier a été résolu. XCTAssertEqual ne fonctionne pas.

Si nous jetons un coup d'œil au code de test, nous constatons qu'il fait en fait ce qui suit (tiré directement de XCTestsAssertionsImpl.h - il est peut-être plus facile de l'afficher à cet endroit) :

#define _XCTPrimitiveAssertEqual(a1, a2, format...) \
({ \
    @try { \
        __typeof__(a1) a1value = (a1); \
        __typeof__(a2) a2value = (a2); \
        NSValue *a1encoded = [NSValue value:&a1value withObjCType:@encode(__typeof__(a1))]; \
        NSValue *a2encoded = [NSValue value:&a2value withObjCType:@encode(__typeof__(a2))]; \
        float aNaN = NAN; \
        NSValue *aNaNencoded = [NSValue value:&aNaN withObjCType:@encode(__typeof__(aNaN))]; \
        if ([a1encoded isEqualToValue:aNaNencoded] || [a2encoded isEqualToValue:aNaNencoded] || ![a1encoded isEqualToValue:a2encoded]) { \
                _XCTRegisterFailure(_XCTFailureDescription(_XCTAssertion_Equal, 0, @#a1, @#a2, _XCTDescriptionForValue(a1encoded), _XCTDescriptionForValue(a2encoded)),format); \
        } \
    } \
    @catch (id exception) { \
        _XCTRegisterFailure(_XCTFailureDescription(_XCTAssertion_Equal, 1, @#a1, @#a2, [exception reason]),format); \
    }\
})

Voilà le problème :

Ce que le test fait en réalité, c'est coder les valeurs dans un fichier de type NSValue et ensuite les comparer. "D'accord," dites-vous, "mais quel est le problème avec ça ?" Je ne pensais pas non plus qu'il y en avait un jusqu'à ce que je fasse mon propre cas de test pour cela. Le problème est que la méthode NSValue -isEqualToValue doit également comparer la valeur de la NSValue type de codage ainsi que sa valeur réelle. Les deux sites doivent être égales pour que la méthode renvoie YES .

Dans votre cas, arr.count est un NSUInteger qui est un typedef de unsigned int . La constante de temps de compilation 3 dégénère vraisemblablement en un signed int au moment de l'exécution. Ainsi, lorsque les deux sont placés dans un NSValue leurs types d'encodage ne sont pas égaux et, par conséquent, les deux ne peuvent pas être égaux selon la règle de l'égalité des chances. -[NSValue isEqualToValue] .

Vous pouvez le prouver avec un exemple personnalisé. Le code suivant fait explicitement exactement ce que XCTAssertEqual lo hace:

// Note explicit types
unsigned int a1 = 3;
signed int a2 = 3;

__typeof__(a1) a1value = (a1);
__typeof__(a2) a2value = (a2);

NSValue *a1encoded = [NSValue value:&a1value withObjCType:@encode(__typeof__(a1))];
NSValue *a2encoded = [NSValue value:&a2value withObjCType:@encode(__typeof__(a2))];

if (![a1encoded isEqualToValue:a2encoded]) {
    NSLog(@"3 != 3 :(");
}

"3 != 3 :(" apparaîtra dans le journal à chaque fois.

Je m'empresse d'ajouter ici que c'est, en fait, un comportement attendu. NSValue es supposée pour vérifier son encodage de type lors des comparaisons. Malheureusement, ce n'est pas ce que nous attendions en testant deux entiers ('égaux').

XCTAssertTrue a une logique beaucoup plus simple, et se comporte généralement comme prévu (encore une fois, voir la source réelle pour savoir comment elle détermine si l'assertion échoue).

5voto

Alex Brown Points 15776

J'ai eu ce problème aussi. Comme @ephemera et @napier l'ont indiqué, il s'agit d'une type question.

Il peut être résolu en fournissant une valeur du type correct, en utilisant les modificateurs de c-litre.

XCTAssertEqual(arr.count, 3ul, @"Wrong array size.");

Vous pouvez trouver le type correct en recherchant le type de retour de la fonction utilisée dans la partie gauche de l'écran. ALT-click sur arr. count :

- (NSUInteger)count;

Maintenant, ALT-cliquez sur NSUInteger pour trouver son type :

typedef unsigned long NSUInteger;

Maintenant, trouvez le format numérique c literal pour unsigned long - google est un bon ami mais cette page fonctionne :

http://www.tutorialspoint.com/cprogramming/c_constants.htm

En guise d'indication rapide, vous devrez peut-être utiliser U (unsigned), L (long) ou F (float), et veiller à écrire 1,0 au lieu de 1 pour obtenir un double. Les minuscules fonctionnent également, comme dans mon exemple ci-dessus.

0voto

ThomasW Points 8078

Une alternative est d'utiliser simplement la coulée :

XCTAssertEqual(arr.count, (NSUInteger)3, @"Wrong array size.");

C'est peut-être la meilleure solution dans l'état actuel des outils, surtout si vous avez un code où vous utilisez XCTAssertEqual et ne veulent pas passer à la XCTAssertTrue .

(J'ai remarqué que @RobNapier a fait cette suggestion dans un commentaire).

0voto

Todd Patterson Points 84

J'ai également été victime de ce problème et je suis très reconnaissant pour les solutions de contournement fournies ici. Pour info, il semble que ce problème ait été corrigé dans la version 5.1 de Xcode.

https://developer.apple.com/library/mac/releasenotes/DeveloperTools/RN-Xcode/xc5_release_notes/xc5_release_notes.html

La macro XCTAssertEqual (anciennement STAssertEquals utilisant OCUnit) compare correctement des valeurs scalaires de types différents sans casting, par exemple, int et NSInteger. Elle ne peut plus accepter les types non scalaires, tels que les structs, pour la comparaison. (14435933)

Je n'ai pas encore effectué la mise à jour de Xcode 5.0.2 mais mon collègue l'a fait, et les mêmes tests XC qui échouaient auparavant à cause de ce problème passent maintenant sans la solution de contournement du casting.

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