Всегда ли в модульном тестировании нужны mock-объекты?

«Всегда ли в модульном тестировании нужны mock-объекты?» — вопрос из категории Тестирование, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Нет, mock-объекты нужны не для всех тестов. Они используются для изоляции тестируемого модуля от его внешних зависимостей (сеть, база данных, файловая система, сложные сервисы).

Когда моки НЕ нужны:

  • При тестировании pure-функций (детерминированных, без побочных эффектов).
  • Для простой логики, не зависящей от других объектов.

Пример теста без мока:

// Pure-функция, тестируется без моков.
func add(_ a: Int, _ b: Int) -> Int {
    return a + b
}

func testAddition() {
    let result = add(2, 2)
    XCTAssertEqual(result, 4)
}

Когда моки НУЖНЫ:

  1. Зависимости медленные или нестабильные (сетевые запросы, доступ к БД).
  2. Нужно проверить взаимодействие (например, был ли вызван метод сервиса с правильными параметрами).
  3. Зависимости имеют сложное состояние или побочные эффекты, которые трудно воспроизвести в тесте.
  4. Тестирование сценариев ошибок, которые сложно вызвать у реальной зависимости.

Пример использования мока для сетевого сервиса:

protocol NetworkServiceProtocol {
    func fetchData(completion: (Data?) -> Void)
}

class MockNetworkService: NetworkServiceProtocol {
    var simulatedData: Data?
    var wasCalled = false

    func fetchData(completion: (Data?) -> Void) {
        wasCalled = true // Проверяем факт вызова
        completion(simulatedData) // Подменяем ответ
    }
}

// В тесте инжектим мок вместо реального сервиса.
let mockService = MockNetworkService()
mockService.simulatedData = Data()
let sut = ViewModel(networkService: mockService)
sut.loadData()
XCTAssertTrue(mockService.wasCalled)