Несколько асинхронных тестов и ожидание
У меня есть несколько тестов, и каждый тест проверяет один и тот же асинхронный метод для разных результатов с заданными параметрами.
Я обнаружил, что для асинхронных тестов мы должны объявить ожидание, дождаться ожидания и выполнить ожидание. Это отлично. Каждый тест работает правильно, когда выполняется отдельно, но когда я пытаюсь запустить весь тестовый класс, некоторые тесты проходят, а другие дают сбой или сбой, когда они работают и проходят нормально.
Я просмотрел в Интернете "быстрые 3 множественных теста с ожиданием", и у каждого, кто объясняет ожидание, есть только пример в одном методе тестирования. Разве нельзя иметь ожидания от нескольких методов в одном классе?
Пример теста следующий:
func testLoginWrongUsernameOrPasswordFailure() {
let viewModel = LoginViewModel()
let loginAPI = APIManager()
let expect = expectation(description: "testing for incorrect credentials")
viewModel.loginWith(username: "qwerty", password: "qwerty", completion: { loginCompletion in
do {
try loginCompletion()
XCTFail("Wrong Login didn't error")
expect.fulfill()
} catch let error {
XCTAssertEqual(error as? LoginError, LoginError.wrongCredentials)
expect.fulfill()
}
})
waitForExpectations(timeout: 10) { error in
XCTAssertNil(error)
}
}
Насколько я знаю, это правильное использование ожиданий, и каждый тест следует той же схеме
По просьбе Роба я предоставлю MCVE здесь https://bitbucket.org/chirone/mcve_test В тестовых классах используется фиктивный API-менеджер, но когда я тестировал реальный, ошибки все равно возникали.
В качестве объяснения для кода модель представления связывается с данным менеджером API, который вызывает сервер и возвращает ответ на модель представления для него, чтобы интерпретировать ошибки или успех.
Первый тест проверяет пустые поля, что проверяет модель представления, а не API Manager. Второй тест проверяет правильность имени пользователя и пароля Третий тест проверяет правильность имени пользователя и пароля
Три теста, запускаемые отдельно, будут работать нормально, однако при запуске всего файла я получу ошибку SIGABRT по следующим причинам:
Ошибка XCTAssertEqual: ("Необязательно (MCVE.LoginError.wrongCredentials)") не равно ("Необязательно (MCVE.LoginError.emptyFields)") -
*** Ошибка подтверждения в -[XCTestExpectation execute], /Library/Caches/com.apple.xbs/Sources/XCTest_Sim/XCTest-12124/Sources/XCTestFramework/Async/XCTestExpectation.m:101
*** Завершение работы приложения из-за необработанного исключения "NSInternalInconsistencyException", причина: "Нарушение API - сделано несколько вызовов -[XCTestExpectation execute] для проверки пустых полей".
SIGABRT обычно происходит во втором тестовом методе, и если вы нажмете кнопку play, то произойдет сбой в одном из методов XCTest, утверждая, что полученная ошибка не является ожидаемой.
Я надеюсь, что MCVE поможет объяснить мою проблему.
1 ответ
Если у вас есть несколько тестов (методов) в одном XCTestCase, не используйте
let expectation = expectation(description: "")
Вместо этого используйте
let expectation = XCTestExpectation(description: "")
В self.expectaion()
используется совместно тестами XCTestCase. В некоторых случаях это приводит к странному поведению. Например, вы можете получить ошибку нарушения API, даже если вы выполнили ожидание ноль раз.
Рефакторинг кода приведен ниже.
func testLoginWrongUsernameOrPasswordFailure() {
let viewModel = LoginViewModel()
let loginAPI = APIManager()
let expect = expectation(description: "testing for incorrect credentials")
viewModel.loginWith(username: "qwerty", password: "qwerty", completion: { loginCompletion in
do {
try loginCompletion()
XCTFail("Wrong Login didn't error")
} catch let error {
XCTAssertEqual(error as? LoginError, LoginError.wrongCredentials)
}
expect.fulfill()
})
waitForExpectations(timeout: 10) { error in
XCTAssertNil(error)
}
}
Если вы все еще получаете следующий сбой, это означает, что ваш обработчик завершения для асинхронного кода вызывает несколько раз. И там, вызывая функцию ожидаем. Несколько раз (). Что не разрешено.
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'API violation - multiple calls made to -[XCTestExpectation fulfill] for testing for empty fields.'
Для ожидания execute () должен вызываться только один раз. Если есть несколько редких сценариев, и вам нужно вызывать функцию ожидаем. Несколько раз () более одного раза, установите следующее свойство.
expectedFulfillmentCount
Пожалуйста, обратитесь по следующей ссылке https://developer.apple.com/documentation/xctest/xctestexpectation/2806572-expectedfulfillmentcount?language=objc
Можно ли ждать множественных ожиданий; да. Вот подпись для метода XCTestCase, который показывает это.
func wait(for: [XCTestExpectation], timeout: TimeInterval)
Существует версия, которая также обеспечивает выполнение ожиданий в том же порядке, в котором они отображаются в for:
массив.
См. Документацию, предоставленную Apple, в XCode->Window->Documentation и API Reference, затем выполните поиск XCTestCase.