简体   繁体   English

在Xcode中检测单元测试是否在运行时运行的正确方法是什么?

[英]What is the proper way to detect if unit tests are running at runtime in Xcode?

When I'm running unit tests, I'd like to skip some code (eg I don't want [[UIApplication sharedApplication] openURL:..] to run). 当我运行单元测试时,我想跳过一些代码(例如我不希望[[UIApplication sharedApplication] openURL:..]运行)。 I'm looking for a runtime check if I'm currently running units tests or not. 我正在寻找运行时检查我是否正在运行单元测试。

I know I have seen code that checks the Objective-C runtime if unit tests are running but am not able to find it anymore. 我知道我已经看过代码检查Objective-C运行时,如果单元测试正在运行,但我再也找不到它了。

You can use this method from google-toolbox-for-mac 您可以使用google-toolbox-for-mac中的 此方法

// Returns YES if we are currently being unittested.
+ (BOOL)areWeBeingUnitTested {
  BOOL answer = NO;
  Class testProbeClass;
#if GTM_USING_XCTEST // you may need to change this to reflect which framework are you using
  testProbeClass = NSClassFromString(@"XCTestProbe");
#else
  testProbeClass = NSClassFromString(@"SenTestProbe");
#endif
  if (testProbeClass != Nil) {
    // Doing this little dance so we don't actually have to link
    // SenTestingKit in
    SEL selector = NSSelectorFromString(@"isTesting");
    NSMethodSignature *sig = [testProbeClass methodSignatureForSelector:selector];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig];
    [invocation setSelector:selector];
    [invocation invokeWithTarget:testProbeClass];
    [invocation getReturnValue:&answer];
  }
  return answer;
}

The reason that NSClassFromString and NSInvocation are used is to allow code compile without linking to xctest or ocunit 使用NSClassFromStringNSInvocation的原因是允许代码编译而不链接到xctest或ocunit

Select the project, and then the test target: 选择项目,然后选择测试目标:

在此输入图像描述

Select Build Settings and choose All and Combined. 选择Build Settings并选择All and Combined。 Type 'preproc' in the search box - you're after Preprocessor Macros. 在搜索框中键入“preproc” - 您在预处理器宏之后。

在此输入图像描述

Add a macro to the Debug configuration called TEST and set it equal to 1 : 将一个宏添加到名为TEST的Debug配置中,并将其设置为1

在此输入图像描述

Then in your code, you can do this: 然后在您的代码中,您可以这样做:

#ifndef TEST
    [[UIApplication sharedApplication] doEvilThingForTesting];
#endif 

Or if you have code that you want to only run in a test environment: 或者,如果您希望在测试环境中运行代码:

#ifdef TEST
    [[UIApplication sharedApplication] doAwesomeTestOnlyThing];
#endif 

It's not exactly runtime , but the unit tester compiles the code before it runs the tests IIRC, so it should be the same effect - you're essentially modifying the code right before running the tests. 它不完全是运行时 ,但单元测试器在运行测试IIRC之前编译代码,因此它应该是相同的效果 - 您实际上是在运行测试之前修改代码。

Rather that sprinkling "am I testing?" 而是洒“我在测试吗?” conditionals throughout production code, I isolate the check to one place: main . 在整个生产代码中的条件,我将支票隔离到一个地方: main There, I check for an alternate application delegate for testing. 在那里,我检查备用应用程序委托进行测试。 If it's available, I use it instead of the the regular application delegate. 如果它可用,我使用它而不是常规应用程序委托。 This completely bypasses the regular launch sequence: 这完全绕过了常规的启动顺序:

int main(int argc, char *argv[])
{
    @autoreleasepool {
        Class appDelegateClass = NSClassFromString(@"TestingAppDelegate");
        if (!appDelegateClass)
            appDelegateClass = [AppDelegate class];
        return UIApplicationMain(argc, argv, nil, NSStringFromClass(appDelegateClass));
    }
}

You can read more about this technique here: How to Easily Switch Your iOS App Delegate for Testing 您可以在此处阅读有关此技术的更多信息: 如何轻松切换您的iOS App代表以进行测试

I think you can check like this for Xcode 7.3 我想你可以为Xcode 7.3这样检查

-(BOOL) isRunningUnitTests
{
    NSDictionary* environment = [ [ NSProcessInfo processInfo ] environment ];
    NSString* theTestConfigPath = environment[ @"XCTestConfigurationFilePath" ];
    return theTestConfigPath != nil;
}

I'm not sure how long this will continue to work, but it works for me right now with Version 9.0 beta 6 (9M214v). 我不知道这会持续多久,但它现在适用于版本9.0 beta 6(9M214v)。

let isTesting = { () -> Bool in
    if let _ = ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] {
        return true
    } else if let testingEnv = ProcessInfo.processInfo.environment["DYLD_INSERT_LIBRARIES"] {
        return testingEnv.contains("libXCTTargetBootstrapInject.dylib")
    } else {
        return false
    }
}()

No build environment or scheme changes are necessary. 不需要构建环境或方案更改。

It appears that there are two different environment variables in play depending on whether you are running a single test case or the entire test suite. 根据您是运行单个测试用例还是整个测试套件,似乎有两个不同的环境变量在起作用。 Also, the variable value also differs depending whether or not you are running in simulator or on a real device. 此外,变量值也会有所不同,具体取决于您是在模拟器中还是在真实设备上运行。

The easiest (and working in Xcode 7 with XCTest!) way to check is to have a look at the process info for a matching xctest bundle: 最简单的(并在Xcode 7中使用XCTest!)检查方法是查看匹配的xctest包的进程信息:

static BOOL isRunningTests(void)
{
    NSDictionary* environment = [[NSProcessInfo processInfo] environment];
    NSString* injectBundle = environment[@"XCInjectBundle"];
    return [[injectBundle pathExtension] isEqualToString:@"xctest"];
}

Source: https://www.objc.io/issues/1-view-controllers/testing-view-controllers/#integration-with-xcode 资料来源: https//www.objc.io/issues/1-view-controllers/testing-view-controllers/#integration-with-xcode

Just use this: 只要用这个:

+ (BOOL)isUnitTestRunning
{
    Class testProbeClass;
    testProbeClass = NSClassFromString(@"XCTestProbe");
    return (testProbeClass != nil);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM