Каков надлежащий способ определения, выполняются ли во время выполнения в Xcode аппаратные тесты?

Когда я запускаю модульные тесты, я бы хотел пропустить некоторый код (например, я не хочу, чтобы [[UIApplication sharedApplication] openURL:..] запускался). Я ищу проверку времени выполнения, если я в настоящее время выполняю тесты модулей или нет.

Я знаю, что видел код, который проверяет время выполнения Objective-C, если юнит-тесты запущены, но я больше не могу его найти.

Ответы

Ответ 1

Вы можете использовать этот метод из 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;
}

Причина, по которой используются NSClassFromString и NSInvocation, - это разрешить компиляцию кода без привязки к xctest или ocunit

Ответ 2

Выберите проект, а затем цель тестирования:

enter image description here

Выберите "Настройки сборки" и выберите "Все" и "Комбинировать". Введите "preproc" в поле поиска - вы выполняете макросы препроцессора.

enter image description here

Добавьте макрос в конфигурацию Debug с именем TEST и установите его равным 1:

enter image description here

Затем в вашем коде вы можете сделать это:

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

Или если у вас есть код, который вы хотите запускать только в тестовой среде:

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

Это не совсем время исполнения, но тестер модулей компилирует код, прежде чем он запускает тесты IIRC, поэтому он должен быть тем же самым эффектом - вы существенно модифицируете код перед запуском тестов.

Ответ 3

Скорее, что посыпать "я тестирую?" условные обозначения во всем производственном коде, я изолирую чек в одном месте: main. Там я проверяю альтернативный делегат приложения для тестирования. Если он доступен, я использую его вместо обычного делегата приложения. Это полностью обходит обычную последовательность запуска:

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

Подробнее об этом методе вы можете прочитать здесь: http://qualitycoding.org/app-delegate-for-tests/

Ответ 4

Я думаю, что вы можете проверить это для Xcode 7.3

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

Ответ 5

Самый простой (и работающий в Xcode 7 с XCTest!) способом проверки - это посмотреть информацию о процессе для соответствующего пакета xctest:

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

Источник: https://www.objc.io/issues/1-view-controllers/testing-view-controllers/#integration-with-xcode

Ответ 6

Я не уверен, как долго это будет продолжаться, но оно работает для меня прямо сейчас с версией 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
    }
}()

Не требуется никаких изменений среды сборки или схемы.

Похоже, что в игре есть две разные переменные среды, в зависимости от того, используете ли вы один тестовый пример или весь комплект тестов. Кроме того, значение переменной также зависит от того, работаете ли вы в симуляторе или на реальном устройстве.

Ответ 7

Просто используйте это:

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