Ответ 1
Благодаря ответу Shaggy Frog мы знаем, что загадочный "мигрирующий", упомянутый в примечаниях к выпуску Xcode, - это мастер, запускаемый при выборе "Редактировать > Рефакторинг > Преобразовать в XCTest". Я собираюсь написать о своем опыте с этим мастером в двух частях. Первая часть - неполный ответ на основной вопрос, вторая часть отвечает второму вопросу.
Часть 1: переход с OCUnit на XCTest
Первое, что вам нужно понять, это то, что для работы мастера вам нужно выбрать цель unit test. Если вы выбрали основную цель, мастер просто не перечисляет цели для конвертации.
Как только я узнал об этом, я смог пройти через волшебник, но в моем случае конечный результат был по-прежнему впечатляющим провалом! Мастер утверждал, что никаких изменений источника не требуется, и что для настройки на XCTest необходимо обновить только необходимые настройки. В конце концов, мастер даже не успел сделать это правильно: он удалил ссылку на структуру SenTestingKit, но не применил ссылку на инфраструктуру XCTest.
В любом случае, вот список изменений, которые мне пришлось вручную сделать, потому что мастер не смог их сделать для меня. Если мастер работает лучше для вас, вам может не понадобиться делать все это.
- Удалите фазу "Запустить Script" из unit test target
- Измените базовый класс всех классов тестовых примеров с
SenTestCase
наXCTestCase
- Измените импортированный заголовок с
<SenTestingKit/SenTestingKit.h>
на<XCTest/XCTest.h>
- В тестовой задаче "Настройки сборки" измените расширение Wrapper с
octest
наxctest
. - Переименуйте все макросы assert от
ST*
доXCT*
(например,STAssertTrue
становитсяXCTAssertTrue
) - Исключение из вышеизложенного:
STAssertEquals
необходимо переименовать вXCTAssertEqual
(обратите внимание на недостающие "s" в конце). Вы узнаете, что вы забыли об этом, если вы получите предупреждение этого компилятора:warning: implicit declaration of function 'XCTAssertEquals' is invalid in C99
- Новые макросы утверждения XCTest не позволяют передавать
nil
в качестве описания сбоя. Например,XCTAssertNotNil(anObject, nil)
невозможен и должен быть изменен наXCTAssertNotNil(anObject)
. Вы узнаете, что у вас есть эта проблема, когда вы получаете эту ошибку компилятора:error: called object type 'NSString *' is not a function or function pointer
. - Если вам нужно передать описание сбоя, для новых макросов утверждения XCTest требуется константное выражение для спецификатора формата, как это делает метод
NSString
classstringWithFormat:
. Вы узнаете, что у вас есть эта проблема, когда вы получаете эту ошибку компилятора:error: expected ')'
. Некоторые примеры:
NSString* formatSpecifier = @"%@";
NSString* failureDescription = @"foo";
// These are OK
XCTAssertNotNil(anObject, @"foo")
XCTAssertNotNil(anObject, @"%@", failureDescription)
// These are not OK
XCTAssertNotNil(anObject, failureDescription);
XCTAssertNotNil(anObject, formatSpecifier, failureDescription);
И последнее, но не менее важное: как уже упоминалось выше, ссылка на раму XCTest должна быть добавлена к цели unit test. Вы узнаете, что вы забыли это, если вы получаете ошибки компоновщика, такие как Undefined symbols for architecture i386: "_OBJC_CLASS_$_XCTestCase", referenced from: foo
.
Обновление Xcode 6. Связывание с XCTest больше не требуется в Xcode 6 (на самом деле XCTest больше не отображается в качестве доступной структуры). Вместо этого установите для параметра сборки CLANG_ENABLE_MODULES значение ДА (отображается в пользовательском интерфейсе как "Включить модули (C и Objective-C)" ). Это приведет к тому, что clang
автоматически свяжется с XCTest, когда увидит оператор #import <XCTest/XCTest.h>
. Подробности доступны в разделе "Модули" документации clang.
Часть 2: Как запустить тесты OCUnit в Xcode 5
В этот момент я получил ошибку компоновщика, которая заставила меня понять, что моя миссия перехода на XCTest потерпела неудачу. Причина: XCTest не является частью SDK 6.1, но я все еще строю свой проект с базовым SDK iOS 6.1 (этот ответ SO объясняет, как интегрировать SDK 6.1 в Xcode 5).
Так как я не могу продолжить миграцию, поэтому мое решение на данный момент состоит в том, чтобы сохранить мои модульные тесты на основе SenTestingKit/OCUnit, пока не найду время для обновления моего приложения до iOS 7. Это то, что я должен был сделать, чтобы запустить единичные тесты:
- Удалите фазу сборки "Запускать Script" из цели unit test. Это все, что требуется для того, чтобы Xcode выполнял модульные тесты посредством действия "Test" (⌘ + U), в то время как цель unit test выбрана.
- Это не идеально, хотя я не хочу переключать цели только для выполнения модульных тестов. Вместо этого я хочу выполнить модульные тесты, пока выбран основной объект. Таким образом, вторым шагом является изменение основной целевой схемы Xcode, так что, когда я запускаю действие "Тест", вместо этого выполняются целевые тесты unit test.
Окончательное решение не так хорошо, как в Xcode 4.x, где модульные тесты выполнялись автоматически каждый раз, когда я запускал основное действие "Run" или "Build". К сожалению, кажется, что я не могу заставить это работать без фазы выполнения "Run Script".