Как стать автором
Обновить

Моки, стабы и фейки: в чем разница и когда что использовать?

Уровень сложностиПростой
Время на прочтение4 мин
Количество просмотров2.5K

Тестирование кода, особенно в сложных системах, зачастую затруднено из-за зависимости от реальных баз данных, внешних сервисов или действий пользователей. Чтобы упростить тестирование, используют заглушки — это упрощенные версии реальных компонентов, которые помогают проверить работу системы без необходимости запускать всё "по-настоящему".

Моки (Mocks), стабы (Stubs) и фейки (Fakes) — это разновидности заглушек, которые заменяют реальные компоненты системы в тестировании. Разница между ними заключается в том, насколько они реалистичны и что именно позволяют протестировать.

Стаб (Stub) — это простая заглушка, которая возвращает заранее определенные ответы, но не содержит логики или сложного поведения.

Фейк (Fake) — это более сложная замена реальной зависимости, которая частично имитирует ее поведение. В отличие от стаба, фейк может содержать простую реализацию логики.

Мок (Mock) — это объект, который не только подменяет реальный компонент, но и позволяет проверять, как с ним взаимодействовали (сколько раз вызвали, с какими параметрами и т. д.).

Очень сложные определения, поэтому для начала давайте отдалимся от IT и рассмотрим пример из жизни.

Представьте, что вы открыли кофейню и хотите протестировать процесс приема заказов. Но есть проблема: у вас пока нет настоящего баристы, который готовит кофе. Как проверить, что кассир правильно принимает заказы?

Стаб (Stub)
Стаб (Stub)

Стаб (Stub) – Заглушка

Вы нанимаете стажера, который просто говорит:

"Ваш заказ принят! Кофе будет готов через 5 минут."

Он всегда отвечает одно и то же, но на самом деле кофе никто не готовит. Вы проверяете, что кассир умеет правильно оформлять заказ, но не тестируете сам процесс приготовления.

Когда использовать?

Если достаточно проверить, что заказ принимается, а готовка не важна.

Фейк (Fake)
Фейк (Fake)

Фейк (Fake) – Упрощенный аналог

Вы ставите в кофейне автомат для кофе, который реально готовит напитки, но выбор ограничен (только эспрессо и американо, без капучино и латте).

Теперь процесс ближе к реальности, но без полного функционала.

Когда использовать?

Когда нужно проверить весь процесс работы, но можно обойтись упрощенной версией.

Мок (Mock)
Мок (Mock)

Мок (Mock) – Проверка взаимодействий

Вы нанимаете человека, который не делает кофе, а просто записывает, какие заказы принимаются и как часто. В конце дня он показывает вам:

  • "10 человек заказали капучино"

  • "5 человек хотели сахар, но кассир забыл добавить"

Здесь вам важно не сам кофе протестировать, а проверить, что кассир правильно взаимодействует с клиентами.

Когда использовать?

Когда важно убедиться, что нужные действия происходят (например, API-запрос отправлен, метод вызван).

А теперь рассмотрим детальнее.

Стаб (Stub) — Заглушка

Когда стоит использовать?

  • Если нужно подменить реальный сервис фиксированными данными.

  • Когда достаточно просто вернуть заранее подготовленный ответ без сложных вычислений.

Пример:

В этом примере тестируется процесс оплаты. Вместо реального платежного шлюза (который может быть недоступен или работать медленно) используется стаб, который всегда возвращает успешный результат.

class OrderService(private val paymentGateway: PaymentGateway) {
    fun processOrder(amount: Double): String {
        return if (paymentGateway.charge(amount)) "Payment Successful" else "Payment Failed"
    }
}

// Стаб-заглушка
class StubPaymentGateway : PaymentGateway {
    override fun charge(amount: Double): Boolean {
        return true // Всегда возвращает успешный платеж
    }
}

// Тест
class OrderServiceTest {
    @Test
    fun `should process order successfully with stub payment gateway`() {
        val stubGateway = StubPaymentGateway()
        val orderService = OrderService(stubGateway)

        val result = orderService.processOrder(100.0)

        assertEquals("Payment Successful", result)
    }
}

💡 Стабы не проверяют, как система взаимодействует с ними, они просто выдают данные.

Фейк (Fake) — Упрощенный аналог

Когда стоит использовать?

  • Когда нужен легковесный аналог реального компонента, который ведет себя похоже, но проще.

  • В тестах, где важно не просто получить статические данные, а динамически их изменять.

Пример:

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

class FakeDatabase : UserRepository {
    private val users = mutableListOf<User>()

    override fun save(user: User) {
        users.add(user)
    }

    override fun findByEmail(email: String): User? {
        return users.find { it.email == email }
    }
}

// Тест с фейковым репозиторием
class UserServiceTest {
    @Test
    fun `should store and retrieve user with fake database`() {
        val fakeDb = FakeDatabase()
        val userService = UserService(fakeDb)

        val user = User("John Doe", "john@example.com")
        userService.register(user)

        val retrievedUser = fakeDb.findByEmail("john@example.com")

        assertEquals(user, retrievedUser)
    }
}

💡 Фейки могут вести себя как настоящие компоненты, но обычно упрощены и не требуют внешних зависимостей (например, реального сервера или БД).

Мок (Mock) — Подделка с проверкой взаимодействий

Когда стоит использовать?

  • Когда важно проверить, как система взаимодействует с зависимостью (например, какие методы вызываются и с какими параметрами).

  • Если нужно протестировать бизнес-логику без реального сервиса, но с контролем вызовов.

Пример:

Здесь тестируется, был ли вызван метод оплаты при оформлении заказа. Используется мок, который позволяет не только подставлять данные, но и проверять, вызывались ли определенные методы с нужными параметрами.

class OrderService(private val paymentGateway: PaymentGateway) {
    fun processOrder(amount: Double): String {
        return if (paymentGateway.charge(amount)) "Payment Successful" else "Payment Failed"
    }
}

// Тест с мок-объектом
class OrderServiceMockTest {
    @Test
    fun `should call payment gateway when processing order`() {
        val mockGateway = mock<PaymentGateway>()
        whenever(mockGateway.charge(any())).thenReturn(true)

        val orderService = OrderService(mockGateway)
        orderService.processOrder(50.0)

        verify(mockGateway).charge(50.0) // Проверяем, что метод вызван с нужным значением
    }
}

💡 Моки полезны, когда важно убедиться, что тестируемый код корректно взаимодействует с зависимостью, а не только получить фиксированные данные.

Резюме

Заглушки — мощный инструмент, который помогает тестировать системы быстрее и эффективнее. Использование стабов, фейков и моков позволяет изолировать тестируемый код от внешних зависимостей, делая тесты надежными и предсказуемыми. Главное — правильно выбирать подходящий тип заглушки в зависимости от целей тестирования, чтобы находить проблемы на ранних этапах и повышать качество продукта.

А больше интересного можно найти в телеграм канале «Тестировщики нужны».

Теги:
Хабы:
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
-1
Комментарии5

Публикации

Истории

Работа

Ближайшие события

19 марта – 28 апреля
Экспедиция «Рэйдикс»
Нижний НовгородЕкатеринбургНовосибирскВладивостокИжевскКазаньТюменьУфаИркутскЧелябинскСамараХабаровскКрасноярскОмск
22 апреля
VK Видео Meetup 2025
МоскваОнлайн
23 апреля
Meetup DevOps 43Tech
Санкт-ПетербургОнлайн
24 апреля
VK Go Meetup 2025
Санкт-ПетербургОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань
14 мая
LinkMeetup
Москва
5 июня
Конференция TechRec AI&HR 2025
МоскваОнлайн
20 – 22 июня
Летняя айти-тусовка Summer Merge
Ульяновская область