我正在尝试使用c宏来确定我是否在进行单元测试,但我对C预处理器还不熟悉。基本上,我试图使用下面的内容。
@implementation thisThing
+(void)thisMethod{
#if TESTING == 1
NSLog(@"TESTING");
#else
NSLog(@"NOT TESTING");
#endif
}
@end
然后在测试文件的标题中
#define TESTING = 1
@interface tester : XCTestCase
@end
@implementation tester
-(void)testTheThing{
XCTAssertEqual(1,1);
}
然而,使用这种方法我仍然只能得到“NOT TESTING”日志消息。任何帮助将不胜感激。
@end
答案 0 :(得分:2)
定义是预处理器宏,这意味着它们只存在于编译时正在编译的文件中。这意味着,如果TESTING == 1
为真,则必须将tester.m
导入thisThing.m
。您可以将-dTESTING=1
定义为Xcode中的编译器指令,但这会使其始终处于该构建配置,即使在未进行测试时也是如此。
更符合您的尝试是在主项目中创建变量,然后在测试项目中,将其引用为extern
变量并将其设置为YES:
主要实施:
BOOL TESTING = NO;
@implementation thisThing
+(void)thisMethod{
if (TESTING) {
NSLog(@"TESTING");
} else {
NSLog(@"NOT TESTING");
}
}
@end
测试文件:
extern BOOL TESTING;
@implementation MyTest
+ (void)initialize
{
TESTING = YES;
}
简单地检查您的应用是否使用XCTest捆绑包启动可能更容易:
BOOL isTesting = [[[NSProcessInfo processInfo] arguments] containsObject:@"-XCTest"];
但一般情况下,最好是您的项目不知道它正在测试中。否则,您将面临不测试实际行为的风险,并使用测试代码污染您的主项目。
答案 1 :(得分:1)
作为实际解释问题中预处理器行为的补充答案:
代码有两个问题会导致不必要的行为。首先,正如Brian指出的那样,因为你既没有#include
也没有#import
带有定义的头文件,当编译.m文件时,常量是不可见的。这是因为预处理器的操作与Objective-C语言完全不同; #directives
形成一个编译时程序,执行" down"正在通过预处理器传递的文件,当到达文件末尾时结束。因此,一旦到达文件末尾,定义就会停止存在;使它们在实现文件中可见的唯一方法是将两个文件拼接成一个"翻译单元"使用#include
或#import
。
因为标头中的定义对.m文件没有影响,所以预处理器正在进行,而根本没有声明TESTING
。您可能希望这会导致编译器错误,但它不会因为预处理器语言处理条件表达式中使用的未定义名称("缺少变量",如果您愿意),通过静默假设它们应该扩展为0
。它永远不会警告您这种行为(这也是考虑使用#ifdef
而不是#if
的原因)。因此,您在.m文件中运行的实际比较会扩展为#if 0 == 1
,并具有现在可预测的结果。
第二个问题是您的定义语法错误。 #define
不使用=
- 在常量名称之后出现的所有内容都是定义的一部分(这是必要的,因为宏也经常用于插入符号)。要将TESTING
定义为1,您需要编写:
#define TESTING 1
否=
(正如您所知,没有;
或其他任何内容)。虽然问题中的定义会导致TESTING
字面上扩展到序列= 1
,但在许多情况下都不会有意义。如果您有#import
个头文件,那么您会在#if
行收到错误,原因很明显= 1
不是数字,并且无法与0进行有意义的比较