> Что проверяют юнит тесты (iOS, Swift)

Уровень: senior · Роль: qa · Категория: Технические вопросы

Компании: ЦРТ, Тинькофф, ЛИПТ Софт

Стек: iOS, Swift

> Пример ответа

Короткий ответ

Юнит тесты проверяют поведение отдельной единицы кода - функции, метода, структуры или класса - в изоляции от остальной системы. Они валидируют корректность логики, обработку граничных случаев, возвращаемые значения и взаимодействие с зависимостями через моки и стабы. Основная цель - быстро подтвердить, что конкретный модуль работает согласно спецификации, и поймать регрессии при изменениях.

Подробное объяснение

Юнит тесты фокусируются на трёх аспектах:

  1. Функциональная корректность - возвращает ли метод ожидаемый результат для заданных входных данных. Это включает happy path, ошибки, пустые значения, крайние случаи (границы диапазонов, nil, пустые коллекции).

  2. Инварианты и контракты - сохраняются ли постусловия: состояние объекта после вызова, неизменяемость данных, корректность типов, отсутствие побочных эффектов за пределами модуля.

  3. Взаимодействие с зависимостями - правильные ли вызовы делает модуль: порядок, аргументы, количество обращений. Для этого используют моки, стабы и шпионы, чтобы изолировать тестируемый код от сети, базы данных, файловой системы и других модулей.

В iOS/Swift юнит тесты дополнительно проверяют:

  • управление памятью (отсутствие retain cycles через weak ссылки);
  • thread safety (если модуль работает с конкурентностью);
  • корректность работы с опциональными значениями и force unwrap;
  • соблюдение протоколов и делегирования.

Важно: юнит тесты не проверяют интеграцию между модулями, UI, производительность в реальных условиях или поведение приложения в целом - это зона интеграционных и UI тестов.

На практике

Для senior QA в iOS контексте важно понимать, что юнит тесты - это не просто проверка "функция вернула true". На практике проверяют:

  • Бизнес-логику - расчёты, валидацию, преобразования данных. Например, тест для модели корзины: добавление товара, изменение количества, расчёт суммы со скидкой.
  • Сетевой слой - через протокол URLProtocol или мок URLSession проверяют декодирование ответов, обработку ошибок, retry логику.
  • Хранилище - Core Data, UserDefaults, Keychain: сохранение, чтение, миграции, обработка повреждённых данных.
  • Вспомогательные утилиты - форматирование дат, парсинг строк, валидация email, работа с опциональными значениями.
  • Реактивные цепочки - если используется Combine или RxSwift: проверка последовательности событий, ошибок, отмены подписки.

Типичный подход - AAA (Arrange, Act, Assert): подготовить данные, выполнить действие, проверить результат. Для изоляции используют dependency injection: тестируемый объект получает мок через инициализатор или свойство.

Пример кода

SWIFT
import XCTest
final class CartTests: XCTestCase {
func testAddItemUpdatesTotalPrice() {
// Arrange
let cart = Cart()
let item = Item(id: 1, name: "Book", price: 100)
// Act
cart.add(item)
// Assert
XCTAssertEqual(cart.totalPrice, 100)
XCTAssertEqual(cart.itemsCount, 1)
}
func testApplyDiscountDoesNotExceedZero() {
// Arrange
let cart = Cart()
cart.add(Item(id: 1, name: "Book", price: 50))
// Act
cart.applyDiscount(80) // 80% скидка
// Assert
XCTAssertEqual(cart.totalPrice, 10)
}
func testRemoveItemDecrementsCount() {
// Arrange
let cart = Cart()
let item = Item(id: 1, name: "Book", price: 100)
cart.add(item)
// Act
cart.remove(item)
// Assert
XCTAssertEqual(cart.itemsCount, 0)
XCTAssertEqual(cart.totalPrice, 0)
}
}

Как отвечать на собеседовании

Начните с чёткого определения: юнит тест проверяет одну единицу кода в изоляции. Затем перечислите, что именно проверяется: входные-выходные данные, граничные случаи, обработку ошибок, взаимодействие с зависимостями. Упомяните, что в Swift для этого используются XCTest и моки через протоколы или DI.

Приведите конкретный пример из практики: как вы тестировали сетевой слой или бизнес-логику. Покажите, что понимаете разницу между юнит, интеграционными и UI тестами. Подчеркните важность тестирования негативных сценариев и краевых случаев - это отличает senior от junior.

Если спросят про покрытие - скажите, что 100% покрытие не самоцель, важнее тестировать критичную логику и частые пути изменения кода. Упомяните, что юнит тесты должны быть быстрыми, детерминированными и не зависеть от внешних ресурсов.

Что проверяет интервьюер

Интервьюер оценивает:

  • Понимание границ юнит тестирования - что входит, а что нет.
  • Умение изолировать зависимости через моки, стабы, DI.
  • Знание типичных сценариев для iOS: работа с URLSession, Core Data, Combine.
  • Способность проектировать тесты: какие кейсы покрывать, как называть тесты, как структурировать.
  • Понимание trade-off: скорость vs глубина, изоляция vs реалистичность.
  • Практический опыт: как вы решали проблемы с флаки-тестами, асинхронностью, глобальным состоянием.

Senior должен показать, что тесты - это инструмент дизайна: они заставляют писать более модульный, тестируемый код. Также важно умение объяснить, когда юнит тесты неэффективны и нужны другие уровни.

Типичные ошибки

  • Тестирование реализации, а не поведения - проверка внутренних вызовов вместо результата. Это делает тесты хрупкими.
  • Отсутствие изоляции - тест обращается к реальной сети, базе данных или файловой системе. Такой тест медленный и недетерминированный.
  • Тестирование только happy path - пропуск обработки ошибок, пустых значений, границ диапазонов.
  • Слишком много моков - тест превращается в проверку того, что мок вызван, а не того, что логика корректна.
  • Игнорирование асинхронности - тест завершается до завершения асинхронной операции, либо использует sleep вместо ожидания через expectation.
  • Тестирование фреймворка - например, проверка того, что URLSession возвращает данные. Это не ваша логика.
  • Слишком крупные юнит тесты - проверка целого сценария с несколькими модулями - это уже интеграционный тест.
  • Пренебрежение тестами для легаси-кода - если код не тестируемый, сначала рефакторят, а не пишут тесты "как есть".

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью