Сегодня хочу вам быстренько рассказать как тестировать асинхронный код.

Представьте ситуацию, что вам надо загрузить данные из интернета и проверить все ли работает нормально, либо еще какую-нибудь задачу, которая выполняется асинхронно. И как же его протестировать? Что если попробовать так же как и обычный синхронный код?!

    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()
        }
    }
}

Надеюсь, кому-нибудь будем полезна данная заметка.

Комментарии (0)