# iOS-Инкубатор. Unit-тесты и TDD
24 ноября 2022
## Тесты
Тесты необходимы для подтверждения работоспостобности как всего приложения, так и отдельных его узлов.

Если можно утвердждать, что для данного объекта его инварианты выполнены, эти утверждения должны быть доказаны тестами и проверяться при модификации объекта, то можно избежать огромного количества проверок как внутри методов объекта, так и при использовании его клиентами.
Мы всегда гоняем тесты. Но выбор за нами -- стоит ли это автоматизировать!
## Test Style Guide
Имя `unit`-теста составное и содержит **4** части:
```swift
func test_login_withValidData_shouldStatusOnSuccess()
```
1. `test` - начало тестовой функции;
2. `login` - тестируемая функция;
3. `withValidData` - параметры тестирования (если нужны);
4. `shouldStatusOnSuccess` - ожидаемый результат теста.
## Частые вопросы на собеседовании
1. Что такое SUT, Dummy, Fake, Stub, Mock?
1. В чем заключается подход AAA при написании теста?
1. Для чего используются функции setUp(), tearDown() при написании TestCase?
1. Для чего используется @testable?
1. Что такое TDD?
### Что такое SUT, Dummy, Fake, Stub, Mock?
SUT -- System Under Test
Согласно Жерару Месарошу, существует 5 видов тестовых двойников:
- Пустышка (dummy)
- Стаб (stub)
- Шпион (spy)
- Мок (mock)
- Фейк (fake)

#### Stub
Заглушки предоставляют готовые ответы на вызовы, сделанные во время теста, обычно не отвечая ни на что, кроме того, что запрограммировано для теста.
#### Dummy
Объекты-пустышки передаются, но фактически никогда не используются. Обычно они нужны просто для заполнения списков параметров.
#### Fake
Фальшивые объекты на самом деле имеют рабочие реализации, но используют некоторые сокращения, которые делают их непригодными для производства.
#### Mock
`Mock` — очень похож на `Stub`, но основан на взаимодействии, а не на состоянии. Это означает, что вы не ожидаете, что `Mock` вернет какое-то значение, но предполагаете, что выполняется определенный порядок вызовов методов.
#### Spy
Шпион: фиктивный фрагмент кода, который перехватывает некоторые вызовы реального фрагмента кода, позволяя вам проверять вызовы без замены всего исходного объекта.
### В чем заключается подход AAA при написании теста?
AAA (Arrange, Act, Assert) паттерн
Если посмотреть на юнит тест, то для большинства можно четко выделить 3 части кода:
- **Arrange** (настройка) — в этом блоке кода мы настраиваем тестовое окружение тестируемого юнита;
- **Act** (выполнение) — выполнение или вызов тестируемого сценария;
- **Assert** (проверка) — проверка того, что тестируемый вызов ведет себя определенным образом.
```swift
// Arrange
let sut = makeSUT()
let taskTypes = TaskType.Inventory.allCases
let notificationSoundName = UNNotificationSoundName(rawValue: "taskNotificationSound.caf")
//Act
let result: [Bool] = taskTypes.map {
sut.makeNotificationSoundName(taskType: TaskType.inventory($0)) == notificationSoundName
}
//Assert
result.forEach { XCTAssertTrue($0, "Ошибка создания звука задания для Inventory") }
```
### Given-When-Then
- `Given` описывает предварительные условия и начальное состояние перед началом теста и допускает любую предварительную настройку, которая может произойти.
- `When` описывает действия, предпринятые пользователем во время теста.
- `Then` описывает результат действий, предпринятых в предложении
```swift=
func test_loadView_shouldHaveCorrectTitle() {
// Given
let sut = makeSUT()
// When
sut.loadViewIfNeeded()
// Then
XCTAssertEqual(
sut.title,
L10n.SearchViewController.title,
"Установлен неверный заголовок"
)
}
```
### Для чего используются функции setUp(), tearDown() при написании TestCase?
- setUp -- для подготовки тестов к запуску
- tearDown -- для очистки после работы тестов
Каждый тест запускает setUp до и tearDown после совей работы!
### Для чего используется @testable?
Применяйте этот атрибут для импорта объявлений для компилируемых модулей с включенным режимом тестинга для доступа к сущностям с уровнем доступа internal как будто они имеют уровень доступа public.

### Что такое TDD?
TDD расшифровывается как Test Driven Development (разработка через тестирование).

TDD -- это не про то, когда пишется тесты на все приложение, а потом пишут код, чтобы приложение заработало.
TDD -- это про то, что каждая строка кода должна сперва быть покрыта тестом.
- Сперва пишем тест
- Он проваливается
- Рефакторим код
- Тест проходит успешно
- Повторить цикл
Со временем, практикуя TDD скорость разработки только увеличтся, но как побочный эффект будет то, что к вашему коду уже будут написаны тесты.
## Задача
Для следующей сессии Инкубатора мы будем реализовывать задачу.
### Написать приложение TODO-List
> [!abstract] Приложение
> Нам нужен список дел, который содержит отдельные задачи. Эти задачи можно добавлять и удалять из списка. Каждый пункт должен уметь быть либо выполненным либо нет и содержать дату выполнения. Кроме того, задачи можно решать только в очередности их добавления.
****
## Дополнительные материалы
- https://www.avanderlee.com/swift/unit-tests-best-practices/
- https://medium.com/capital-one-tech/using-stub-vs-mock-in-ios-unit-testing-634ec4cc6a10