---
name: unit-testing-ios-app
description: Правила написания unit-тестов для iOS приложений
---
# Правила написания unit-тестов

Для запуска тестов используй только команду make test.

## Когда применять

- При написании новых unit-тестов для iOS-проекта
- При рефакторинге существующих тестов для соответствия стандартам
- При тестировании бизнес-логики сервисов и ViewModels
- При создании мок-клиентов для тестирования интеграции с сервером
- При написании параметризированных тестов для множества сценариев

## Основные принципы

### 1. Технологии тестирования
- **Swift Testing** (import Testing) - основной фреймворк
- **@Test** для тестовых функций
- **#expect** для проверок
- **#require** для разворачивания опционалов

### 2. Правила написания тестов

#### Синтаксис тестов

См. примеры синтаксиса в [references/EXAMPLE.md](references/EXAMPLE.md).

#### Описания тестов
- **Обязательно** добавляй описание теста на русском языке в аннотации `@Test`
- **Используй** краткие и понятные описания того, что тестируется
- **Пример**: `@Test("Должен возвращать правильный результат для валидных данных")`

#### Работа с опционалами
- **Всегда** разворачивай опционалы перед проверками с помощью `try #require()`
- **Не используй** знаки вопроса (?) в проверках `#expect`
- **Пример**: `let value = try #require(optionalValue)` затем `#expect(value == expected)`

#### Асинхронные тесты
- **Добавляй `throws`** если в тесте есть `try`
- **Не добавляй `throws`** если нет `try` в тесте
- **Добавляй `async`** для асинхронных тестов
- **Не добавляй `async`** если в тесте нет await

#### Проверки Bool условий
- **Не используй** равенство для Bool значений
- **Используй** прямое сравнение: `#expect(isTrue)` или `#expect(isFalse)`
- **Пример**: `#expect(condition)` вместо `#expect(condition == true)`

#### Проверка конкретных ошибок
- **Используй** `#expect(throws: ErrorType)` для проверки конкретных типов ошибок
- **Не используй** do-catch блоки для проверки ожидаемых ошибок

См. примеры в [references/EXAMPLE.md](references/EXAMPLE.md).

#### Параметризированные тесты
- **Используй** параметризированные тесты когда нужно протестировать несколько сценариев с разными аргументами и одинаковой логикой
- **Добавляй** `arguments:` в аннотацию `@Test` с массивом значений
- **Параметр функции** должен соответствовать типу аргументов
- **Не используй в аргументах** ожидаемый результат - в аргументах должны быть только вводные данные
- **Группируй** тесты с одинаковым сценарием или ожидаемым результатом
- **Преимущества**: сокращает дублирование кода, делает тесты более читаемыми, легко добавлять новые сценарии

См. примеры в [references/EXAMPLE.md](references/EXAMPLE.md).

#### Комментарии в тестах
- **Лишние комментарии в тестах не нужны** - код должен быть самодокументируемым
- **Для простых сценариев** комментарии не нужны вообще
- **Для сложной логики** можно добавить краткий комментарий внутри `#expect`
- **Не используй** обычные комментарии (`//`) над `#expect`
- **Чем короче комментарий**, тем лучше

См. примеры в [references/EXAMPLE.md](references/EXAMPLE.md).

### 3. Структура тестов
- **Один тестовый файл на модуль**
- **Тестировать бизнес-логику** в сервисах
- **Тестировать ViewModels** с моками
- **Не тестировать UI** напрямую
- **Не дублировать** одинаковые сценарии в разных тестах
- **Пиши простые тесты**, в тестах не должно быть сложной логики и проверки разных сценариев типа "if shouldThrow {} else {}"

### 4. Тестирование интеграции с сервером
- **Используй только мок-клиенты** для тестирования запросов к серверу и для работы со Swift Data (ModelContainer)
- **Никогда не отправляй** реальные запросы на сервер в тестах
- **Создавай общие мок-клиенты** в папке с тестами для переиспользования в разных тестовых файлах
- **Группируй мок-клиенты** по функциональности (например, `MockProgressClient`, `MockAuthClient`)
- **Используй dependency injection** для передачи мок-клиентов в тестируемые сервисы

## Заключение

При написании unit-тестов всегда следуй этим правилам для обеспечения консистентности и правильности тестового кода в проекте.
