MockK: що це, ключові поняття та синтаксис

Автор: IT Sectr Опубліковано: 2026-04-08 Час читання: 8 хв

MockK — це Kotlin-first фреймворк для створення mock-об'єктів, розроблений спеціально для екосистеми Kotlin з урахуванням її мовних особливостей: корутин, extension-функцій, data class і sealed class. На відміну від Mockito, який портовано на Kotlin з Java, MockK спочатку проєктувався під Kotlin-синтаксис і не потребує додаткових плагінів для роботи з final-класами. За даними MockK.io, бібліотека використовується більш ніж у 40% Kotlin-проєктів з модульним тестуванням.

Головне

  • MockK — Kotlin-орієнтована бібліотека для мокування з підтримкою корутин і фіч мови.
  • mockk() — основний метод створення мок-об'єкта, аналогічний Mockito.mock().
  • every { } — блок для налаштування поведінки мока (stubbing) у декларативному стилі.
  • coEvery / coVerify — спеціальні конструкції для роботи з suspend-функціями корутин.
  • Relaxed mock — мок, який повертає значення за замовчуванням без явного стабінгу.

Що таке MockK?

MockK — це бібліотека для створення mock-об'єктів, написана на Kotlin і оптимізована під його синтаксис. Вона вирішує ті самі завдання, що й Mockito — ізоляція тестованого коду від залежностей — але робить це з використанням Kotlin-специфічних конструкцій: лямбд, DSL, reified generics і suspend-функцій.

Основна перевага MockK перед портованими рішеннями — натівна підтримка Kotlin. У Mockito мокування final-класу потребує opt-in (mockito-inline), а статичних методів — mockStatic. MockK підтримує це за замовчуванням, оскільки Kotlin-класи за замовчуванням final, і обхід цього обмеження вбудовано в архітектуру бібліотеки.

Версія 1.13.12 (2024) — стабільний реліз, що підтримує Kotlin 2.0, K2-компілятор і мультиплатформенні проєкти (KMP). MockK також працює з Kotlin/Native і Kotlin/JS, що робить його єдиним вибором для KMP-проєктів, де ні Mockito, ні EasyMock не застосовні.

MockK спроєктовано з урахуванням специфіки Kotlin і використовує мовні можливості — reified generics, DSL з лямбдами, inline-функції — для забезпечення лаконічного та типобезпечного API без втрати продуктивності.

Як працює MockK

Механізм MockK заснований на байткод-інструментації через бібліотеку ByteBuddy (як і Mockito), але обгортає її в Kotlin-friendly DSL. Замість ланцюжків when().thenReturn() MockK використовує лямбда-блоки every { } і coEvery { }, які виглядають як природне розширення мови. Під капотом MockK перехоплює виклик всередині лямбди, аналізує метод і аргументи через рефлексію та зіставляє із записаними правилами стабінгу.

Базовий синтаксис MockK

Блок every { mock.method() } returns value читається як «щоразу, коли викликається метод, повертати значення». Такий декларативний синтаксис ближчий до Kotlin-стилю та виключає плутанину з порядком аргументів у when(). Завдяки reified generics Kotlin, тип мока виводиться автоматично без явного зазначення класу.

kotlin
val repository = mockk<UserRepository>()

// Stubbing: кожен виклик findById(1) повертає користувача
every { repository.findById(1) } returns User("Alice")

// Виклик і перевірка
val result = repository.findById(1)
assertEquals("Alice", result.name)

Relaxed mock: менше boilerplate

На відміну від Mockito, де кожен метод потрібно налаштовувати явно, MockK підтримує relaxed mock — мок, який повертає «розумні» значення за замовчуванням для будь-якого методу: порожній список для List, 0 для Int, порожній рядок для String. Це різко скорочує обсяг підготовчого коду.

kotlin
// Relaxed mock — всі методи повертають значення за замовчуванням
val api = mockk<ApiService>(relaxed = true)

// Не потребує стабінгу — поверне порожній список
println(api.getUsers()) // []

Створення моків і релаксованих моків

MockK пропонує кілька способів створення мок-об'єктів: mockk<T>() для строгого мока (кожен метод має бути явно налаштований), mockk<T>(relaxed = true) для релаксованого мока та spyk(obj) для створення шпигуна на реальному об'єкті.

ФункціяТипПоведінка без стабінгу
mockk()Строгий мокКидає виняток при виклику не-стабнутого методу
mockk(relaxed = true)Релаксований мокПовертає значення за замовчуванням
spyk()ШпигунВикликає реальний метод, якщо не налаштовано стаб
slot()Argument CaptorЗахоплює аргумент для перевірки

Вибір між строгим і релаксованим моком залежить від контексту. Строгий мок гарантує, що тест не використовує методи, поведінка яких не визначена — це підвищує надійність. Релаксований мок зручний для швидкого прототипування тестів, де не важливі всі залежності. На практиці рекомендується починати зі строгого мока і перемикатися на relaxed лише тоді, коли стабінг займає більше рядків, ніж сам тест.

Stubbing: налаштування поведінки з every блоком

Блок every — це центральна конструкція стабінгу в MockK. Всередині лямбди описується виклик методу з конкретними аргументами, а після повертається значення через returns, викидається виняток через throws або обчислюється відповідь через answers.

Різні способи стабінгу

MockK підтримує всі сценарії, необхідні для тестування: повернення значення, викид винятку, обчислення відповіді на основі аргументів, кілька відповідей по порядку (послідовність викликів).

kotlin
// Повернення значення
every { repo.findById(1) } returns User("Alice")

// Викид винятку
every { repo.findById(999) } throws NotFoundException()

// Динамічна відповідь
every { repo.save(any()) } answers {
    val user = firstArg<User>()
    user.copy(id = 42)
}

// Послідовність відповідей
every { repo.findAll() } returnsMany listOf(
    listOf(User("Alice")),
    listOf(User("Bob")),
    emptyList()
)

Verify і coVerify для корутин

Verify у MockK аналогічний Mockito.verify() за змістом, але використовує Kotlin DSL: verify { mock.method() }. Для suspend-функцій використовується coVerify { mock.suspendMethod() }, який коректно працює з корутинами і не потребує спеціального раннера.

Перевірка кількості викликів

MockK підтримує ті самі модифікатори, що й Mockito: exactly(1), atLeast(2), atMost(5), wasNot(Called). Синтаксис мінімалістичний — модифікатор передається першим аргументом у verify { }.

kotlin
// Перевірка: метод викликано рівно 1 раз
verify(exactly = 1) { repo.save(any()) }

// Перевірка порядку викликів
verifySequence {
    repo.save(any())
    repo.flush()
}

// coVerify для suspend-функцій
coVerify { api.fetchUsers() }

Slot: захоплення аргументів

Для перевірки аргументів використовується slot() — аналог ArgumentCaptor. Slot оголошується до виклику, передається в every або verify, і після виконання тесту містить захоплене значення.

kotlin
val userSlot = slot<User>()

verify { repo.save(capture(userSlot)) }

assertEquals("Alice", userSlot.captured.name)

Анотації MockK та інтеграція з JUnit

MockK надає анотації @MockK і @RelaxedMockK для створення моків через ініціалізацію в JUnit 5. Розширення MockKExtension автоматично створює моки перед кожним тестом і очищає після — аналогічно MockitoExtension, але з підтримкою relaxed-режиму.

Приклад з MockKExtension

Анотація @InjectMockKs (або альтернатива @MockK з явним створенням об'єкта) впроваджує моки в тестований екземпляр. Це скорочує boilerplate і робить код тесту чистішим.

kotlin
@ExtendWith(MockKExtension::class)
class UserServiceTest {

    @MockK
    lateinit var repository: UserRepository

    @InjectMockKs
    lateinit var service: UserService

    @Test
    fun `getUser returns user from repository`() {
        every { repository.findById(1) } returns User("Alice")
        assertEquals("Alice", service.getUser(1)?.name)
    }
}

MockK vs Mockito: що обрати для Kotlin

Вибір між MockK і Mockito залежить від складу команди та типу проєкту. Mockito має більшу екосистему, більше прикладів та інтеграцій, але MockK надає чистіший Kotlin-синтаксис і натівну підтримку мовних фіч. Для нових Kotlin-проєктів MockK рекомендується як більш ідіоматичне рішення.

КритерійMockKMockito
СинтаксисKotlin DSL (every, verify)Java-стиль (when, thenReturn)
КорутиниcoEvery, coVerify (натівно)Потребує дод. бібліотек
Final classПідтримується за замовчуваннямПотребує mockito-inline
KMPПідтримуєтьсяНе підтримується
Relaxed mockВбудованийНемає аналога
ПопулярністьЗростає в Kotlin-спільнотіДомінує в Java та гібридних проєктах

Для проєктів на чистому Kotlin (без Java-класів) MockK кращий: менше boilerplate, натівна підтримка корутин, немає сюрпризів з final-класами. Для гібридних проєктів або команд з Java-бекграундом Mockito залишається робочим варіантом — обидві бібліотеки можна використовувати в одному проєкті через різні модулі. При міграції з Mockito на MockK достатньо замінити анотації @Mock на @MockK і переписати блоки when().thenReturn() у формат every { }.

Часті запитання

Чим relaxed mock відрізняється від звичайного мока в MockK?

Relaxed mock повертає значення за замовчуванням для всіх не-стабнутих методів (порожній список, 0, null), не кидаючи винятків. Звичайний (строгий) mock потребує явного стабінгу кожного методу — інакше тест падає. Relaxed mock зручний для швидких тестів, strict — для надійних.

Як мокувати extension-функції в MockK?

MockK підтримує мокування extension-функцій через mockkStatic(). Це можливо тому, що extension-функції в Kotlin — це статичні методи з першим параметром-приймачем. Для кожної extension-функції потрібно вказати клас, у якому вона оголошена.

Чи працює MockK з Kotlin Multiplatform?

Так, MockK підтримує Kotlin Multiplatform (KMP) для common-коду. На платформах JVM, Native і JS можна використовувати спільний API mockk(), every, verify. Це робить MockK єдиним вибором для KMP-проєктів, де Mockito не працює.

Як перевірити порядок викликів у MockK?

Використовуйте verifySequence { } — блок, у якому виклики вказуються строго в очікуваному порядку. Якщо реальний порядок відрізняється, verifySequence кине виняток із зазначенням першого неспівпавшого виклику.

Чи можна використовувати MockK і Mockito в одному проєкті?

Так, технічно це можливо, але не рекомендується. Конфлікти можуть виникнути на рівні байткод-інструментації (ByteBuddy vs mockito-inline). Якщо проєкт уже використовує Mockito, міграція на MockK може бути поступовою через ізоляцію модулів.

Підсумки

  • MockK — Kotlin-first бібліотека для мокування з натівною підтримкою мови.
  • every { } — декларативний DSL для налаштування поведінки моків.
  • coEvery / coVerify — підтримка suspend-функцій корутин без додаткових залежностей.
  • Relaxed mock — мок зі значеннями за замовчуванням, що скорочує boilerplate.
  • @MockK / @InjectMockKs — анотації для автоматичного створення моків у JUnit 5.
  • MockK vs Mockito — MockK кращий для чистих Kotlin-проєктів і KMP.
  • verifySequence — перевірка строгого порядку викликів методів.

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також