【问题标题】:Why does passing an NSString object to the "format" parameter of XCTAssertTrue cause a build error?为什么将 NSString 对象传递给 XCTAssertTrue 的“格式”参数会导致构建错误?
【发布时间】:2013-11-18 15:57:02
【问题描述】:

在尝试使用 XCTest 测试我的应用程序时,执行以下操作时出现构建错误:

#import <XCTest/XCTest.h>

@interface MyTests : XCTestCase

@end

@implementation MyTests

- (void)testExample
{
    NSString *str = @"foo";
    XCTAssertTrue(YES, str); // Parse issue: Expected ')'
}

@end

但如果我这样做,我不会收到构建错误:

#import <XCTest/XCTest.h>

@interface MyTests : XCTestCase

@end

@implementation MyTests

- (void)testExample
{
    XCTAssertTrue(YES, @"foo"); // this is just fine...
}

@end

我得到的构建错误是:

Parse issue: Expected ')' 

它会在“str”中的“s”下方放置一个箭头。

我发现我可以通过改变来解决这个问题

XCTAssertTrue(YES, str)

XCTAssertTrue(YES, @"%@", str)

但我就是不知道为什么会有所作为。有人可以解释一下为什么会这样吗?

【问题讨论】:

    标签: ios objective-c xcode macos xctest


    【解决方案1】:

    编写XCT... 宏以接受格式字符串——字符串本身是可选的(因此编写XCTAssertTrue(YES) 是有效的),但它们必须是常量字符串。如果没有格式字符串,您无法将对象传递到宏中,这就是为什么 XCTAssertTrue(YES, @"%@", str) 可以工作,但 XCTAssertTrue(YES, str)XCTAssertTrue(NO, nil) 不能。

    【讨论】:

    • 但是在使用字符串字面量XCTAssertTrue(YES,@"foo") 的情况下,这真的不是NSString * 对象吗?
    • 字符串文字 @"foo" 在运行时确实会转换为 NSString * 对象,但在编译时,字符串文字有额外的含义。 NS_FORMAT_FUNCTION 属性让编译器知道函数接受 printf 样式的字符串文字作为格式字符串,以及其他对象作为输入;如果你一直遵循宏的实现,你最终会找到_XCTFailureHandler 函数,它被标记为NS_FORMAT_FUNCTION(6,7)。如果您尝试使用非字符串文字对象调用该函数,您将收到警告或错误。
    • 宏错误报告可能有点奇怪——因为预处理器本质上是将宏的内容复制并粘贴到您的代码中,失败(例如上面的那个)可能会向上传播并给您一些无关紧要的信息错误信息,就像你看到的那样。
    【解决方案2】:

    在实现的深处,代码是这样做的:

        @"" format
    

    如果format 是常量字符串文字,编译器会连接这些字符串。如果format 是其他任何内容,则会出现编译器错误。

    【讨论】:

      【解决方案3】:

      有时需要将预定义的文本传递给断言,因此:

      XCTAssertTrue(YES, @"foo"); // this is just fine...
      

      原来如此

      #define FOO @"foo"
      XCTAssertTrue(YES, FOO); // this is just fine too...
      

      所以我会做这样的事情:

      #define DBUEqualityTestFailed @"Equality test failed"
      
      // test
      DBNumber *n1 = [@((int)1) dbNumberFromIntValue];
      
      XCTAssertTrue(*(int *)[n1 valuePointer] == 1, DBUEqualityTestFailed);
      XCTAssertTrue([n1 valuePointer] == [n1 valuePointer], DBUEqualityTestFailed);
      XCTAssertTrue(*(int *)[n1 valuePointer] == *(int *)[n1 valuePointer], DBUEqualityTestFailed);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-06-24
        • 1970-01-01
        • 1970-01-01
        • 2020-03-08
        • 1970-01-01
        • 1970-01-01
        • 2012-02-20
        • 1970-01-01
        相关资源
        最近更新 更多