Итак, я решил это следующим образом.
Краткий обзор проблемы:
Мне нужно было запустить несколько тестов подряд: test1
, test2
, test3
, test4
. Каждый тест устанавливал ожидание, и последний шаг в тесте соответствовал ожиданию, затем тест завершался, и запускался следующий.
Однако в Xcode 8 тесты теперь выполняются в случайном порядке. Хотя это хорошо с той точки зрения, что если это модульные тесты, то они должны выполняться в произвольном порядке, но ваши тесты ломаются, если они разработаны не как модульные тесты, а как end -до конца тестов.
Например, в моем случае это ломает тесты, потому что в первом тесте пользователь входит в систему и настраивает некоторые данные и т. д. Затем второй тест проверяет математику, затем третий тест синхронизирует данные с сервером, затем четвертый удаляет все это и синхронизируется с сервером. Когда запускается первый тест, во время сборки сценарий оболочки инициирует БД сервера из файла MSYQL, а затем во время запуска приложения AppDelegate устанавливает новую базу данных Core Data для приложения. Таким образом, если мне нужно запускать приложение заново после каждого теста, сценарий оболочки повторно инициализирует серверную БД и вызывает повторную инициализацию локальной базы данных Core Data DB. Это нарушит последующие тесты (это сквозной тест, последующие тесты зависят от состояния приложения и сервера определенным образом после запуска предыдущего теста).
Вместо того, чтобы настраивать четыре разных исходных базы данных Core Data и четыре разных сценария инициализации сервера (что было бы огромной головной болью и сделало бы сквозное тестирование экспоненциально более трудоемким для управления всякий раз, когда у нас было изменение схемы), или пришлось бы не забудьте запускать без создания каждого теста вручную подряд, вместо этого я объединил все четыре метода тестирования в один действительно длинный метод тестирования, используя следующую тактику.
Решение
Во-первых, в классе XCTestCase я установил свойство ожидания теста:
@property (nonatomic, strong) XCTestExpectation *endOfTestExpectation;
В конце test1
в моем классе XCTestCase я заменил его существующее ожидание этим новым ожиданием, например так:
self.endOfTestExpectation = [self expectationWithDescription:
@"endOfTestExpectation"];
[self waitForExpectationsWithTimeout:900
handler:^(NSError * _Nullable error) {
/* Code moved from test4's expectation completion block goes here */
}
Для каждого с test1
по test3
я переместил код, который находился внутри исходного блока завершения теста, в новый метод, названный с completion1
по completion3
. Для test4
я переместил код внутри исходного блока завершения ожидания в блок завершения endOfTestExpectation
в конце метода test1
.
Затем я переименовал методы с test2
по test4
, назвав их с t3st2
по t3st4
(я знаю, быстро и грязно; вы должны выбрать что-то более описательное после того, как вы заработаете). В конце метода completion1
я вызываю t3st2
; в конце completion2
я звоню t3st3
; в конце completion3
я звоню t3st4
; и в конце completion4
я звоню [self.endOfTestExpectation fulfill];
.
Это на самом деле оказывается лучше, чем старый способ, потому что по-старому, даже если первый тест не пройден, последующие тесты все равно будут выполняться! Теперь, где бы ни происходило XCTFail
, все просто останавливается, и мы не тратим время на прогон остальных, если меня перевели в SO :D
person
CommaToast
schedule
22.09.2016