0Pricing
Swift Academy · Урок

Тестирование асинхронного кода (XCTest)

Пишите асинхронные тесты с XCTest: помечайте тесты как async , используйте await и throws , проверяйте сбои и тайм-ауты, а также результаты структурированного параллелизма.

«Тестирование асинхронного кода (XCTest)» — бесплатный урок Swift Academy на CoddyKit. Это урок 3 из 3. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Swift Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Swift Academy содержит 3 уроков всего.

Асинхронные тесты: основы

XCTest поддерживает асинхронные тесты. Делайте тесты небольшими и детерминированными:

  • Объявляйте асинхронные тесты и используйте ожидание
  • Используйте выбрасывание ошибок и do/catch для обработки сбоев
  • Заменяйте задержки небольшими имитациями и заглушками

Успешный асинхронный случай

Сделайте тест асинхронным и вызовите SUT с ожиданием. Пишите обычные проверки, например XCTAssertEqual.

import XCTest
import Foundation

// System Under Test (SUT)
func fetchValue() async -> Int {
    try? await Task.sleep(nanoseconds: 50_000_000)
    return 42
}

final class AsyncBasicsTests: XCTestCase {
    func testFetchValue_returns42() async {
        let v = await fetchValue()
        XCTAssertEqual(v, 42)
    }
}

Асинхронное выбрасывание ошибок и проверки

Используйте тесты с асинхронностью и выбрасыванием ошибок. Для конкретных ошибок перехватывайте их и сопоставляйте с образцом, чтобы намерение оставалось понятным.

import XCTest

enum NetError: Error { case offline }

func loadNumber(online: Bool) async throws -> Int {
    try await Task.sleep(nanoseconds: 30_000_000)
    if !online { throw NetError.offline }
    return 7
}

final class AsyncThrowingTests: XCTestCase {
    func testLoadNumber_success() async throws {
        let n = try await loadNumber(online: true)
        XCTAssertEqual(n, 7)
    }

    func testLoadNumber_offline_throws() async {
        do {
            _ = try await loadNumber(online: false)
            XCTFail("Expected error")
        } catch NetError.offline {
            // expected
        } catch {
            XCTFail("Unexpected error: \\(error)")
        }
    }
}

Параллельные результаты

Структурированное конкурентное выполнение легко тестировать: используйте async let и проверяйте итоговый результат. Делайте задержки очень короткими, чтобы избежать нестабильных тестов.

import XCTest

func compute(_ x: Int) async -> Int {
    try? await Task.sleep(nanoseconds: 10_000_000)
    return x * x
}

final class ParallelTests: XCTestCase {
    func testParallel_asyncLet_sumsSquares() async {
        async let a = compute(2)
        async let b = compute(3)
        let sum = await (a + b)
        XCTAssertEqual(sum, 13) // 4 + 9
    }
}

Тестирование ограничения времени

Тестируйте ограничения времени, устраивая гонку операции и короткой задачи sleep. Используйте очень малые интервалы, чтобы тесты оставались быстрыми и стабильными.

import XCTest

enum TimeoutError: Error { case timedOut }

func withTimeout<T>(
    seconds: Double,
    operation: @escaping () async throws -> T
) async throws -> T {
    try await withThrowingTaskGroup(of: T.self) { group in
        group.addTask { try await operation() }
        group.addTask {
            try await Task.sleep(nanoseconds: UInt64(seconds * 1_000_000_000))
            throw TimeoutError.timedOut
        }
        let first = try await group.next()!
        group.cancelAll()
        return first
    }
}

final class TimeoutTests: XCTestCase {
    func testTimeout_timesOutFast() async {
        do {
            _ = try await withTimeout(seconds: 0.01) {
                try await Task.sleep(nanoseconds: 50_000_000) // slower than timeout
                return "OK"
            }
            XCTFail("Expected timeout")
        } catch TimeoutError.timedOut {
            // expected
        } catch {
            XCTFail("Unexpected error: \\(error)")
        }
    }
}

Ожидания (старый подход)

Для старых обратных вызовов по-прежнему используйте ожидания/ожидание завершения. Для нового кода отдавайте предпочтение асинхронным тестам.

import XCTest

// Legacy API with a completion handler
func legacyFetch(_ completion: @escaping (String) -> Void) {
    Task { try? await Task.sleep(nanoseconds: 20_000_000); completion("done") }
}

final class ExpectationTests: XCTestCase {
    func testLegacy_withExpectation() {
        let exp = expectation(description: "legacy finishes")
        legacyFetch { value in
            XCTAssertEqual(value, "done")
            exp.fulfill()
        }
        wait(for: [exp], timeout: 1.0)
    }
}

Современный стиль асинхронных тестов

Быстрая проверка: как лучше всего тестировать асинхронную функцию?

Итоги

Итоги: используйте асинхронные методы XCTest с ожиданием, проверяйте успешные и ошибочные пути, делайте задержки очень короткими, а ожидания оставляйте для старых обратных вызовов.

Часто задаваемые вопросы

Урок «Тестирование асинхронного кода (XCTest)» бесплатный?

Да — полный текст урока «Тестирование асинхронного кода (XCTest)» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Swift Academy, подпишись на CoddyKit PRO. Курс Swift Academy содержит 3 уроков всего.

Чему я научусь в уроке «Тестирование асинхронного кода (XCTest)»?

Пишите асинхронные тесты с XCTest: помечайте тесты как async , используйте await и throws , проверяйте сбои и тайм-ауты, а также результаты структурированного параллелизма. Ты практикуешь Swift Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Swift Academy?

Предыдущий опыт не требуется. Swift Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 3.

Сколько времени занимает урок «Тестирование асинхронного кода (XCTest)»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Swift Academy?

Да. Каждый урок Swift Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Производитель и потребитель, конвейеры, тайм-ауты
  2. Переход от устаревших обратных вызовов и Combine к async/await
  3. Тестирование асинхронного кода (XCTest)
← Назад к Swift Academy