XCTAssertEqual错误:(“3”)不等于(“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."); 

我对XCTAssertEqual有什么不了解? 为什么最后的断言失败?

Xcode 5的testing也遇到了一些麻烦。 它似乎仍然有一些奇怪的行为错误 – 但是我发现你的特定XCTAssertEqual无法正常工作的明确原因。

如果我们看一下testing代码,我们可以看到它实际上做了以下操作(直接从XCTestsAssertionsImpl.h – 在这里查看可能更容易):

 #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); \ }\ }) 

这是问题:

testing实际上是在将值编码成NSValue ,然后进行比较。 “好吧,”你说,“但那有什么问题呢?” 直到我为自己做了一个testing用例,我才觉得有一个。 问题是NSValue的-isEqualToValue还必须比较NSValue的编码types及其实际值。 两者必须相同才能返回YES

在你的情况下, arr.count是一个NSUInteger ,它是unsigned int的typedef。 编译时常量3可能在运行时退化为带signed int 。 因此,当两个被放入一个NSValue对象,他们的编码types是不相等的,因此两个不能相等根据-[NSValue isEqualToValue]

你可以用一个自定义的例子certificate这一点。 下面的代码明确地做了XCTAssertEqual所做的事情:

 // 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 :("每次都会出现在日志中。

我急于在这里补充说,事实上,这是预期的行为。 NSValue 应该在比较时检查它的types编码。 不幸的是,这只是testing两个('相等')整数时所期望的。

XCTAssertTrue一句, XCTAssertTrue有更直接的逻辑,并且行为与预期的一样(同样,请参阅实际来源以确定断言是否失败)。

我也有这个问题。 正如@ephemera和@napier所示,这是一个types问题。

它可以通过使用c-literal修饰符提供正确types的值来解决。

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

您可以通过查找左侧使用的函数的返回types来find正确的typesALT-click arr。 count

 - (NSUInteger)count; 

现在在ALT上点击NSUInteger来查找它的types:

 typedef unsigned long NSUInteger; 

现在findC字面数字格式为无符号的长 – 谷歌是一个很好的朋友,但这个网页的工作原理:

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

作为一个快速提示,您可能需要使用U(无符号)L(long)或F(float),并确保写入1.0而不是1来获得双精度值。 小写字母也有效,就像我上面的例子。

如果别人正在寻找像我这样的双重比较的问题(上面的解决scheme不适用于float和double),请尝试:

 XCTAssertEqualWithAccuracy(number.doubleValue, 12.34, 0.01); 

((\expression式1)和(\expression式2)之间的差异>(\ a精度)))时生成失败。

一种替代方法是使用铸造:

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

这可能是当前工具状态的最佳解决scheme,尤其是如果您有代码的情况下,您正在使用XCTAssertEqual并且不想切换到XCTAssertTrue

(我注意到@RobNapier在评论中提出了这个build议。)

我也受到这个问题的困扰,非常感谢这里提供的解决方法。 Quick FYI,看来这是在Xcode 5.1版本中修复的。

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

XCTAssertEqualmacros(以前使用OCUnit的STAssertEquals)正确地比较了不同types的标量值,例如int和NSInteger。 它不能再接受非标量types,比如结构体。 (14435933)

我还没有从Xcode 5.0.2升级,但我的同事已经和以前由于这个问题失败了相同的XCtesting现在传递没有施法解决方法。