Тестирование iOS: dispatch_once вызывается дважды. Сначала в приложении, второй в тесте. Проблемы с наблюдателями

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

Когда я запускаю XCTTests, его создание создается во второй раз.

+ (instancetype)urlSchemeManager { static dispatch_once_t onceToken; static UrlSchemeManager* _sharedInstance; dispatch_once(&onceToken, ^{ _sharedInstance = [UrlSchemeManager new]; }); return _sharedInstance; } 

Это приводит к двум различным случаям. Это не проблема, если я просто использую его для модульного теста. Но в тесте интеграции, когда я регистрирую наблюдателя для urlSchmemeManager, я получаю EXC_BAD_ACCESS, потому что он уже наблюдался rootViewController (в пользовательском интерфейсе).

В RootViewController:

 UrlSchemeManager * schemeManager = [GlobalSpace globalSpace].urlSchemeManager; [schemeManager addObserver:self forKeyPath:OBSERVER_KEY_URL_SCHEME_MANAGER_CONTENT_MORE options:NSKeyValueObservingOptionNew context:nil]; 

Кто-нибудь есть идея, как я могу обойти эту проблему?

У меня была такая же проблема, когда dispatch_once вызывается несколько раз при запуске набора тестов. Я исправил это, удалив класс singleton из Target Membership of Test.

После того, как вы это сделали, убедитесь, что ваша тестовая цель зависит от вашего приложения в «Фазах сборки», чтобы тест все еще знал о классе.

После этого тест должен выполняться, и синглтон должен быть создан только один раз.

Ответ Майка правильный! Просто добавьте дополнительную информацию. Это очень сложная проблема. Кажется, что цель приложения и тестовая цель скомпилированы отдельно. Однако во время выполнения двоичный код для тестов вводится в пространство приложения. Поскольку обычно задача компилятора заключается в обнаружении повторяющихся символов, а процесс компиляции отличается, может случиться, что у вас есть два экземпляра класса во время выполнения. Каждый экземпляр класса с собственным набором статических переменных. Это супер странно. Из этого могут вытекать тонны странного поведения. Включая выполнение double dispatch_once_t .

Я столкнулся с этими проблемами в своих кокадоподах . Все контейнеры в вашем подфайле по умолчанию привязаны ко всем целям. В результате при запуске XCTest у вас будут дубликаты кланов во время выполнения. Решение состоит в том, чтобы указать ваши контейнеры для каждой цели. В моем случае, например. Я сделал:

 source 'https://github.com/CocoaPods/Specs.git' platform :ios, '7.0' target 'MyApp', :exclusive => true do pod 'AFNetworking' pod 'ObjectiveRecord', :head ... end target 'MyApp Tests', :exclusive => true do pod 'KIF', '~> 3.0', :configurations => ['Debug'] end inhibit_all_warnings! 

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

  • Как написать единичный тест для получения асинхронности nsnotification?
  • Функция прерывания XCTAssert
  • Пойманный запрос NSInternalInconsistencyException для rect при недопустимом indexPath
  • Невозможно выполнить тесты из командной строки через xcodebuild
  • validateForInsert терпит неудачу, когда я устанавливаю связь между двумя действительными объектами
  • как поделиться некоторыми контейнерами в двух целях с помощью podfile
  • Невозможно использовать классы Swift внутри Objective-C unit test
  • Файл "XXX-Swift.h" не найден в тестовом проекте
  • Простой XCTest для UITest не работает постоянно?
  • Импорт XCTest в динамическую структуру
  • Журнал экспорта XCode 7 UITest
  • Давайте будем гением компьютера.