Сегодня хочу вам быстренько рассказать как тестировать асинхронный код.
Представьте ситуацию, что вам надо загрузить данные из интернета и проверить все ли работает нормально, либо еще какую-нибудь задачу, которая выполняется асинхронно. И как же его протестировать? Что если попробовать так же как и обычный синхронный код?!
func testAscynFunction() {
someAsyncFunction()
}
func someAsyncFunction() {
let bg = DispatchQueue.global(qos: .background)
bg.asyncAfter(deadline: .now() + 5) {
XCTAssert(false, "Something went wrong")
}
}
Такой тест вернет нам положительный результат, так как метод не будет ждать всех наших асинхронных задач.
Для решения такой проблемы в тестах есть одна замечательная вещь: XCTestExpectation
XCTestExpectation задает то, сколько раз должен выполниться асинхронный метод и только после всех этих выполнений тест окончится и скажет были ли ошибки. Вот пример:
class TestAsyncTests: XCTestCase {
// 1) объявляем expectation
var expectation: XCTestExpectation!
func testWithExpectationExample() {
//2) Инициализируем его
expectation = expectation(description: "Testing Async")
//3) задаем то количество раз, сколько должен исполниться метод expectation.fulfill()
expectation.expectedFulfillmentCount = 5
for index in 0...5 {
someAsyncFunctionWithExpectation(at: index)
}
//5) Ожидаем пока исполнится нужное количество expectation.fulfill()
// в противном же случае по истечении 60 сек метод сам выдаст ошибку, так как не дождался
waitForExpectations(timeout: 60) { (error) in
if let error = error {
XCTFail("WaitForExpectationsWithTimeout errored: (error)")
}
}
}
func someAsyncFunctionWithExpectation(at index: Int) {
let bg = DispatchQueue.global(qos: .background)
bg.asyncAfter(deadline: .now() + 5) { [weak self ] in
XCTAssert(false, "Something went wrong at index (index)")
//4) Именно его исполнение и подсчитывает expectation.expectedFulfillmentCount
self?.expectation.fulfill()
}
}
}
Надеюсь, кому-нибудь будем полезна данная заметка.
Автор: ArtMartiros