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不了解什么?为什么最后一个断言失败了?
答案 0 :(得分:47)
我对Xcode 5的测试也遇到了很多麻烦。它仍然看起来很奇怪,有些奇怪的行为 - 但是我发现了你的特定XCTAssertEqual
无效的明确原因。
如果我们查看测试代码,我们会看到它实际执行以下操作(直接从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); \
}\
})
问题在于:
测试实际上做的是将值编码为NSValue
然后进行比较。 “好的,”你说,“但那有什么问题?”在我为自己制作测试用例之前,我认为没有一个。问题是NSValue的-isEqualToValue
还必须比较NSValue的编码类型及其实际值。 两者必须相等才能返回YES
。
在您的情况下,arr.count
是NSUInteger
,其类型定义为unsigned int
。编译时常量3
可能在运行时退化为signed int
。因此,当两者放入NSValue
对象时,它们的编码类型不相等,因此根据-[NSValue isEqualToValue]
两者不能相等。
您可以使用自定义示例来证明这一点。以下代码明确地完成了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
假设检查其类型编码。不幸的是,这不是我们在测试两个('相等')整数时所期望的。
XCTAssertTrue
具有更直接的逻辑,并且通常表现得如预期的那样(再次,请参阅确定断言是否失败的实际来源)。
答案 1 :(得分:5)
我也遇到过这个问题。正如@ephemera和@napier指出的那样,这是一个类型的问题。
可以通过使用c-literal修饰符提供正确类型的值来解决。
XCTAssertEqual(arr.count, 3ul, @"Wrong array size.");
您可以通过查找左侧使用的函数的返回类型找到正确的类型 - ALT-click
上的count
:
- (NSUInteger)count;
现在ALT点击NSUInteger
以查找其类型:
typedef unsigned long NSUInteger;
现在找到unsigned long的c文字数字格式 - 谷歌是一个好朋友,但这个页面有效:
http://www.tutorialspoint.com/cprogramming/c_constants.htm
作为这里的快速提示,您可能需要使用U(无符号)L(长整数)或F(浮点数),并确保编写1.0而不是1来获得双精度。小写也可以,如上例所示。
答案 2 :(得分:3)
如果其他人正在通过像我这样的双重比较来寻找问题主导(上面的解决方案不能用于浮动和双重),请尝试:
XCTAssertEqualWithAccuracy(number.doubleValue, 12.34, 0.01);
((一个表达式1)和(\一个表达式2)之间的差异是>(\一个精度)))时产生失败。
答案 3 :(得分:0)
另一种方法是使用铸造:
XCTAssertEqual(arr.count, (NSUInteger)3, @"Wrong array size.");
对于当前工具状态,它可能是最佳解决方案,尤其是如果您有大量使用XCTAssertEqual
并且不想切换到XCTAssertTrue
的代码。
(我注意到@RobNapier在评论中提出了这个建议。)
答案 4 :(得分:0)
我也被这个问题所困扰,非常感谢这里提供的解决方法。 快速FYI,似乎已在Xcode 5.1版本中修复。
XCTAssertEqual宏(以前使用OCUnit的STAssertEquals)正确地比较不同类型的标量值而不进行强制转换,例如int和NSInteger。它不能再接受非标量类型,例如结构,以进行比较。 (14435933)
我还没有从Xcode 5.0.2升级但是我的同事已经升级了,之前由于这个问题导致失败的XC测试现在没有使用强制转换方法。