TGViewer
Мобильный трудоголик Мобильный трудоголик @hardworkerit · 1.65K subscribers
Post #116 879
🔢 XCTest уходит в прошлое? Разбираем плюсы и минусы Swift Testing.

С выходом Swift Testing многие задумались о миграции с XCTest. Но так ли всё гладко, как обещает Apple? Давайте разберём реальные подводные камни и лайфхаки для перехода.


🤔 Чем Swift Testing отличается от XCTest?

1️⃣ Обнаружение тестов.
🔹 XCTest: использует XCTestCase + Objective-C runtime.
🔹 Swift Testing: макросы @Test + Swift ориентированный подход.

2️⃣ Выполнение тестов.
🔹 XCTest: выполняется последовательно (один за другим).
🔹 Swift Testing: выполняется параллельно (каждый тест в отдельной Task).

3️⃣ Синтаксис.
Разница в коде:

// XCTest  
func testLogin() { XCTAssertEqual(result, expected) }

// Swift Testing
@Test func login() { #expect(result == expected) }



⚠️ Главные проблемы миграции.

1️⃣ Ассерты вне контекста Task.
Swift Testing требует, чтобы проверки (#expect) выполнялись только внутри Task.

// Старая схема (XCTest)
func testAsync() {
DispatchQueue.main.async {
XCTAssertEqual(result, 42)
}
}

// Неправильная миграция (упадёт в Swift Testing)
@Test func asyncTest() {
DispatchQueue.main.async {
#expect(result == 42) // Ошибка: вне контекста Task
}
}

// Правильная миграция
@Test func asyncTest() async { // 1. Объявляем async тест
let result = await withCheckedContinuation { continuation in
DispatchQueue.main.async {
continuation.resume(returning: 42) // 2. Возвращаем результат в контекст Task
}
}

#expect(result == 42) // 3. Проверяем УЖЕ внутри Task-контекста
}


Ключевые моменты:
🔸 Тест должен быть async — это автоматически создаёт контекст Task.
🔸 Все асинхронные операции, которые не поддерживают async/await оборачиваются в withCheckedContinuation.
🔸 #expect вызывается после получения результата, но внутри области теста.

2️⃣ Проблемы с общим состоянием.
Параллельное выполнение тестов могут вызвать гонки данных.

♣️ Пример:

actor Counter {
var count = 0

func increment() {
count += 1
}
}

@Test func testA() async {
await Counter.shared.increment()
#expect(await Counter.shared.count == 1) // Может упасть, если testB запустится раньше!
}

@Test func testB() async {
await Counter.shared.increment()
}


✅ Решение:
Использование @Suite(.serialized) для последовательного выполнения:

@Suite(.serialized)
struct CriticalTests {
@Test func testA() {
}

@Test func testB() {
}
}



3️⃣ Наследование тестов не работает.
В XCTest можно было наследовать XCTestCase и автоматически получать все тесты родителя. В Swift Testing так не работает — тесты нужно дублировать.

Что делать:
🔸 Для простых сценариев использовать параметризованные тесты.
🔸 Для сложных, пока оставьте XCTest и мигрируйте постепенно.


💡 Вывод:
На Swift Testing стоит переходить если у вас современный проект, который использует Swift Concurrency и вам необходимо параллельное выполнение тестов.

Мой совет: Начинайте с гибридного подхода — подключайте Swift Testing для новых модулей, а старые тесты оставляйте в XCTest.


➡️ Подписаться на канал
Мобильный трудоголик
  • ❤ 26
  • 👍 19
  • 🔥 2
More from @hardworkerit
  1. Oct 9, 2026👨‍💻 Умение адаптироваться - важный навык айтишника, который часто недооценивают. В ИТ не…
  2. Oct 8, 2026🈸 Apple обяжет разработчиков поддерживать iPhone Duo. Apple опубликовала требования к при…
  3. Oct 6, 2026🔢 Swift 6.4: новая диагностика ретейн циклов. В Swift 6.4 появилась новая диагностика, ко…
  4. Oct 4, 2026🔢 SwiftUI: определение угла раскрытия iPhone Duo. В iOS 27.1 появился модификатор .onHing…
  5. Oct 2, 2026👣 Архитекторы, тестировщики и кодеры. Создаем мультиагентную команду Разработка с ИИ-аген…
  6. Oct 1, 2026🔢 Работа с Picture-in-Picture в iOS. Picture-in-Picture - системная функция iOS, которая…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →