【问题标题】:XCTAssertEqual error: ("3") is not equal to ("3")XCTAssertEqual 错误:(“3”)不等于(“3”)
【发布时间】:2013-10-11 06:26:04
【问题描述】:
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 有哪些不了解的地方?为什么最后一个断言失败?

【问题讨论】:

  • 其他一些很棒的匹配器库是:OCHamcrest 和 Expecta。 .还有 Kiwi 和 Cedar - 成熟的测试框架,带有很好的内置匹配器库。 . (以防万一您还没有尝试过这些)。

标签: objective-c ocunit xctest


【解决方案1】:

如果其他人像我一样正在寻找由双重比较导致的问题(上述解决方案不适用于浮动和双重),请尝试:

XCTAssertEqualWithAccuracy(number.doubleValue, 12.34, 0.01);

当 ((\a expression1) 和 (\a expression2) 之间的差 > (\a accuracy))) 时生成失败。

【讨论】:

    【解决方案2】:

    我也被这个问题所困扰,非常感谢这里提供的解决方法。 仅供参考,这似乎已在 Xcode 5.1 版本中修复。

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

    XCTAssertEqual 宏(以前使用 OCUnit 的 STAssertEquals)可以正确比较不同类型的标量值而无需强制转换,例如 int 和 NSInteger。它不再接受非标量类型(例如结构)进行比较。 (14435933)

    我还没有从 Xcode 5.0.2 升级,但我的同事已经升级了,之前由于这个问题而失败的相同 XC 测试现在在没有强制转换解决方法的情况下通过。

    【讨论】:

      【解决方案3】:

      另一种选择是只使用强制转换:

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

      根据工具的当前状态,这可能是最好的解决方案,尤其是如果您的代码经常使用 XCTAssertEqual 并且不想切换到 XCTAssertTrue

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

      【讨论】:

        【解决方案4】:

        我也遇到过这个问题。正如@ephemera 和@napier 所指出的,这是一个type 问题。

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

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

        您可以通过查找左侧使用的函数的返回类型来找到正确的类型 - ALT-click on arr.count

        - (NSUInteger)count;
        

        现在按住 ALT 键单击 NSUInteger 以查找其类型:

        typedef unsigned long NSUInteger;
        

        现在找到 unsigned long 的 c 文字数字格式 - google 是一个好朋友,但这个页面有效:

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

        作为一个快速提示,您可能需要使用 U(无符号)L(长整数)或 F(浮点数),并确保写入 1.0 而不是 1 以获得双精度数。小写也可以,就像我上面的例子一样。

        【讨论】:

        • 如果您希望您的测试同时在 32 位和 64 位上运行,我认为这不起作用。使用3ul 会导致 32 位失败。
        【解决方案5】:

        我在 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.countNSUInteger,它是 unsigned int 的 typedef。编译时常量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 顺便提一下,它的逻辑要简单得多,并且行为通常符合预期(再次,请参阅实际来源,了解它如何确定断言是否失败)。

        【讨论】:

        • 值得注意的是,正确的解决方法是简单地包含类型信息。 XCTAssertEqual(arr.count, (NSUInteger)3, @"Wrong array size.");
        • 谢谢,更简单的方法是:XCTAssertEqual(arr.count, 3U, @"Wrong array size.");
        • 最好使用(NSUInteger)3 而不是3U,因为对于 64 位和 32 位编译,NSUInteger 的类型定义不同。对于 64 位,NSUInteger 是 unsigned long,而对于 32 位,NSUInteger 是 unsigned int
        • 或者使用我从@WayneHartman 在link 中给出的答案中学到的XCTAssertEqualWithAccuracy(arr.count, 3, 0.000000001);
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多