В чем разница между моками и стабами в тестировании?

Ответ

Моки и стабы — это виды тестовых заглушек (test doubles), но с разными целями.

Стаб (Stub)

  • Цель: Предоставить тестируемому коду предопределённые данные, заменяя реальную зависимость.
  • Не проверяет взаимодействие, только возвращает фиктивные данные.
  • Используется для изоляции тестируемого модуля.

Пример стаба на Swift:

protocol DataService {
    func fetchUser() -> String
}

class StubDataService: DataService {
    func fetchUser() -> String {
        return "Test User" // Жёстко заданное значение
    }
}

Мок (Mock)

  • Цель: Проверить взаимодействие (какие методы были вызваны, с какими параметрами).
  • Записывает вызовы и позволяет делать утверждения (assertions) о них.
  • Используется для проверки поведения (behavior verification).

Пример мока на Swift:

class MockDataService: DataService {
    var fetchUserCallCount = 0

    func fetchUser() -> String {
        fetchUserCallCount += 1 // Фиксация факта вызова
        return ""
    }
}

// В тесте:
// let mock = MockDataService()
// ... выполнение теста ...
// XCTAssertEqual(mock.fetchUserCallCount, 1)

Ключевое отличие:

  • Стаб — для подмены данных (state).
  • Мок — для проверки вызовов (behavior).

Ответ 18+ 🔞

Ну, блядь, смотри, сейчас я тебе так разложу про моки и стабы, что ты, сука, сам себе позавидуешь. Это ж, ёпта, основа основ, а народ путается, как слепой кот в сортире.

Представь, что ты тестируешь какую-нибудь, блядь, хитрую жопу — класс, который должен отправить письмо. У него там зависимость от какого-то MailService. И вот тут начинается магия.

Стаб (Stub) — это тупой, блядь, подставной мужик. Его задача — просто, сука, не отсвечивать и дать тебе то, что ты попросил. Никаких претензий, никаких проверок. Ты ему: «Слушай, fetchUser(), верни мне "Вася Пупкин"». Он тебе: «На, блядь, "Вася Пупкин"». И всё. Он не запоминает, вызывали его или нет. Он просто заглушка, которая возвращает предсказуемый ответ, чтобы твой основной код не пошёл в интернет или в базу данных, а спокойно, сука, отработал. Это как подставить другу стул, когда он пьяный идёт — просто чтобы не упал, хуле.

// Это стаб, ёпта. Тупо возвращает строку.
class StubDataService: DataService {
    func fetchUser() -> String {
        return "Test User" // На, получи, и не пизди.
    }
}

А теперь, блядь, Мок (Mock) — это уже не просто подставной мужик, а самый настоящий стукач, ёбана. Его задача — следить и доносить. Ты его внедряешь, а он, сука, записывает: ага, метод sendEmail вызвали один раз, ага, передали такой-то адрес. А потом ты к нему подходишь в конце теста и спрашиваешь: «Ну что, сучара, вызывали тебя?». И он тебе: «Да, блядь, вызывали ровно один раз, вот с такими параметрами». И если вызовов не было или было не то — ты ему по ебалу, и тест падает. Это проверка поведения, а не состояния. Не «что вернул», а «что сделал».

// А это уже мок, стукач ебаный.
class MockDataService: DataService {
    var fetchUserCallCount = 0 // Счётчик, блядь, ведёт.

    func fetchUser() -> String {
        fetchUserCallCount += 1 // Зафиксировал вызов, падла.
        return "" // Возвращает хоть хуй с горы, не в этом суть.
    }
}
// Потом в тесте: XCTAssertEqual(mock.fetchUserCallCount, 1) — «Ну что, вызывали? Признавайся!»

Короче, сука, резюмирую:

  • Стаб — это дурак, который просто даёт нужные тебе данные. Используется, чтобы изолировать код от внешнего мира. Состояние (state).
  • Мок — это стукач, который шпионит, что и как вызывалось. Используется, чтобы проверить, а правильно ли твой код общается с другими. Поведение (behavior).

Запомни, а то будешь, как тот Герасим, только «Му-му» мычать, когда тебя спросят, в чём разница. Всё, вопрос закрыт, иди работай.