Mockito — що це, ключові поняття та принцип роботи

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

Mockito — це фреймворк з відкритим кодом для створення mock-об'єктів у модульних тестах Java та Kotlin, який дозволяє ізолювати код, що тестується, від зовнішніх залежностей. За його допомогою розробник підміняє реальні репозиторії, API-клієнти та бази даних контрольованими заглушками із заданою поведінкою. За даними Mockito.org, бібліотека використовується більш ніж у 60% Java-проектів, які застосовують модульне тестування.

Головне

  • Mockito — бібліотека для створення mock-об'єктів, що замінюють реальні залежності в тестах.
  • Mock — об'єкт-заглушка, який імітує поведінку реального компонента.
  • Stubbing — налаштування значення, що повертається під час виклику методу мока.
  • Verify — перевірка того, що метод було викликано з певними аргументами.
  • @InjectMocks — автоматичне впровадження mock-залежностей в об'єкт, що тестується.

Що таке Mockito?

Mockito — це бібліотека з відкритим кодом для створення mock-об'єктів (заглушок) у модульних тестах на Java, Kotlin та інших мовах JVM. На відміну від JUnit, який відповідає за запуск тестів, Mockito вирішує проблему ізоляції — підміняє реальні залежності класу, що тестується, передбачуваними об'єктами.

Без моків тестування методу, який звертається до бази даних або зовнішнього API, вимагає налаштування реального середовища — розгортання БД, запуску сервера. Mockito замінює ці залежності об'єктами з фіксованою поведінкою: метод repository.findById(1) завжди повертає заданий об'єкт User, не звертаючись до бази.

Архітектура Mockito заснована на паттерні Proxy (для інтерфейсів та класів). Бібліотека генерує підклас або проксі для вказаного типу і перехоплює всі виклики методів, повертаючи значення за замовчуванням або задані через when().thenReturn().

Як працює Mockito

Принцип роботи Mockito будується на трьох базових операціях: створення мока, налаштування поведінки (stubbing) та перевірка викликів (verification). Кожна операція використовує статичні методи з класу org.mockito.Mockito — найзавантажуванішого класу в екосистемі Java за статистикою Maven Central. Всі виклики методів мока записуються в пам'ять, що дозволяє пізніше перевірити їх через verify.

Три кроки тесту з Mockito

Типовий тест з Mockito складається з трьох фаз: Arrange — створення моків та налаштування стабів через when().thenReturn(), Act — виклик методу, що тестується, Assert — перевірка результату через assertEquals та verify(мок). Такий підхід називається AAA (Arrange-Act-Assert).

Базовий приклад з моком репозиторію

Розглянемо найпростіший тест, де Mockito підміняє репозиторій користувачів. Метод when().thenReturn() налаштовує мок так, щоб виклик findById повертав заздалегідь підготовлений об'єкт User.

java
// Створюємо мок репозиторію
UserRepository mockRepo = mock(UserRepository.class);

// Налаштовуємо поведінку: при findById(1) повернути користувача
when(mockRepo.findById(1)).thenReturn(new User("Alice"));

// Перевіряємо, що метод дійсно було викликано
User result = mockRepo.findById(1);
assertEquals("Alice", result.getName());
verify(mockRepo).findById(1);

Створення mock-об'єктів

Mockito надає два способи створення моків: статичний метод mock(Class) та анотацію @Mock з ініціалізацією через MockitoAnnotations.openMocks(). Перший спосіб компактний для одного-двох моків, другий зручний, коли залежностей багато — анотації скорочують boilerplate-код.

Через статичний метод mock()

Метод mock() приймає клас і повертає об'єкт-заглушку, який можна налаштувати через when().thenReturn(). Всі неналаштовані методи повертають значення за замовчуванням: 0 для чисел, false для boolean, null для об'єктів.

java
ApiClient apiClient = mock(ApiClient.class);
Database database = mock(Database.class);

Через анотацію @Mock з JUnit 5

Анотація @Mock у поєднанні з @ExtendWith(MockitoExtension.class) автоматично створює моки для всіх полів тестового класу. Розширення MockitoExtension відповідає за ініціалізацію перед кожним тестом.

java
@ExtendWith(MockitoExtension.class)
class UserServiceTest {

    @Mock
    private UserRepository userRepository;

    @InjectMocks
    private UserService userService;

    @Test
    void getUserShouldReturnUserFromRepo() {
        when(userRepository.findById(1)).thenReturn(new User("Alice"));
        User result = userService.getUser(1);
        assertEquals("Alice", result.getName());
    }
}

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

Stubbing — це процес визначення того, що має повернути метод мока при виклику з певними аргументами. Базовий синтаксис: when(mock.method(args)).thenReturn(value). Для різних сценаріїв Mockito пропонує кілька варіантів then-методів.

МетодПризначення
thenReturn(value)Завжди повертає вказане значення
thenThrow(exception)Викидає виняток при виклику
thenAnswer(answer)Обчислює значення, що повертається, динамічно
thenCallRealMethod()Викликає реальний метод (частковий мок)

Динамічна відповідь через thenAnswer

Коли значення, що повертається, залежить від аргументів виклику, використовується thenAnswer з лямбдою. Це корисно для імітації роботи з реальними даними — наприклад, генерації ID на основі переданого об'єкта.

java
when(repository.save(any())).thenAnswer(invocation -> {
    User user = invocation.getArgument(0);
    user.setId(42);
    return user;
});

Verify: перевірка взаємодій з моком

Verify — це унікальна можливість Mockito, яку не надають старіші бібліотеки mock-об'єктів (EasyMock, jMock).

Verify робить тести більш надійними, оскільки перевіряє не тільки значення, що повертається, але й побічні ефекти — виклики методів, які не повертають результат (void-методи). Метод verify(mock).methodName(args) перевіряє, чи було викликано певний метод мока із зазначеними аргументами. Це дозволяє тестувати не тільки результат, але й процес — факт звернення до залежності.

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

За замовчуванням verify перевіряє, що метод було викликано рівно один раз. Якщо потрібна інша кількість — використовується times(n), atLeast(n), never() та інші модифікатори з класу Mockito.

java
// Перевірка кількості викликів
verify(repository, times(3)).save(any());
verify(repository, never()).delete(any());
verify(repository, atLeastOnce()).findById(1);

// Перевірка порядку викликів
InOrder inOrder = inOrder(repository);
inOrder.verify(repository).save(any());
inOrder.verify(repository).flush();

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

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

java
ArgumentCaptor<User> captor = ArgumentCaptor.forClass(User.class);
verify(repository).save(captor.capture());
assertEquals("Alice", captor.getValue().getName());

Анотації @Mock та @InjectMocks

@Mock та @InjectMocks — дві ключові анотації Mockito, які значно скорочують boilerplate-код. @Mock створює мок для поля, а @InjectMocks впроваджує всі моки з тестового класу в об'єкт, що тестується, через конструктор, сеттер або поле.

Механізм @InjectMocks намагається впровадити залежності в наступному порядку: конструктор з найбільшою кількістю аргументів, сеттер за типом, приватне поле. Якщо жоден спосіб не спрацював — об'єкт залишається з null-залежностями, і тест впаде з NullPointerException.

Правила використання @InjectMocks

Важливо розуміти: @InjectMocks не аналізує типи полів — він підставляє будь-який мок, сумісний за типом. Якщо в класі два поля одного типу — Mockito може впровадити неправильний мок. У таких випадках рекомендується використовувати явний конструктор з передачею моків.

Mockito в Android-проектах

У Android-розробці Mockito застосовується разом з JUnit для тестування ViewModel, Repository та UseCase. Оскільки ці класи виконуються на JVM без Android-контексту, Mockito підміняє їхні залежності — Room DAO, Retrofit API, SharedPreferences — на стаби з передбачуваною поведінкою.

Налаштування Gradle для Mockito

Для підключення Mockito в Android-проект достатньо додати залежність mockito-core або mockito-inline (остання підтримує мокування final-класів та статичних методів). Версія 5.12.0 (2024) включає підтримку Java 21 та покращену інтеграцію з JUnit 5.

kotlin
// build.gradle.kts (module)
dependencies {
    testImplementation("org.mockito:mockito-core:5.12.0")
    testImplementation("org.mockito:mockito-junit-jupiter:5.12.0")
}

Mockito та PowerMock: застаріла практика

Раніше для мокування статичних методів і конструкторів вимагався PowerMock — розширення, що працювало через байткод-інструментацію. Починаючи з Mockito 5.x з mockito-inline, ця можливість вбудована безпосередньо: mockStatic(ClassName.class) дозволяє мокувати статичні методи без додаткових бібліотек.

Тестування ViewModel з Mockito

Типовий сценарій: ViewModel викликає метод репозиторію і трансформує результат у UI-стан. Mockito підміняє репозиторій, а тест перевіряє, що ViewModel коректно обробляє успішну відповідь та помилку. При використанні архітектури Clean Architecture моки створюються для кожного шару: DataSource, Repository та UseCase — це дозволяє тестувати кожен шар ізольовано.

  • success case — when(repo.getData()).thenReturn(Result.success(data)) → перевіряємо state = Success(data).
  • error case — when(repo.getData()).thenReturn(Result.error(exception)) → перевіряємо state = Error(message).
  • loading state — verify, що ViewModel встановила isLoading = true перед викликом репозиторію.

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

Чим Mockito відрізняється від MockK?

Mockito — бібліотека для Java та Kotlin, що використовує проксі та рефлексію. MockK — Kotlin-first бібліотека з підтримкою корутин, extension-функцій та final-класів без додаткової конфігурації.

Як створити мок для final-класу в Mockito?

Починаючи з Mockito 2.1, мокування final-класів підтримується через opt-in. У версії 5.x (mockito-inline) це включено за замовчуванням. Достатньо додати залежність mockito-inline та використовувати стандартний mock() метод.

Що таке Spy в Mockito?

Spy — це частковий мок, який за замовчуванням викликає реальні методи, але дозволяє перевизначити деякі з них через when().thenReturn(). Spy корисний для тестування legacy-коду, коли не можна переписати весь клас.

У чому різниця між thenReturn та thenAnswer?

thenReturn завжди повертає одне й те саме значення, незалежно від аргументів. thenAnswer обчислює значення, що повертається, на основі invocation — аргументів виклику, самого мока, стану. Для динамічних відповідей завжди використовуйте thenAnswer.

Чому verify важливий для тестів з моками?

Verify перевіряє не тільки результат, але й процес — факт звернення до залежності. Це критично для сервісів, які повинні зберігати дані або надсилати сповіщення. Без verify тест не виявить, що метод не викликав save() або send().

Підсумки

  • Mockito — бібліотека для створення mock-об'єктів, стандарт de facto для мокування в Java та Kotlin.
  • Моки створюються через mock(Class) або анотацію @Mock з MockitoExtension.
  • Stubbing через when().thenReturn() задає поведінку методів мока.
  • Verify перевіряє факт та кількість викликів методів мока із зазначеними аргументами.
  • @InjectMocks автоматично впроваджує моки в об'єкт, що тестується.
  • Android-інтеграція — Mockito використовується для тестування ViewModel, Repository та UseCase.
  • ArgumentCaptor захоплює аргументи виклику для детальної перевірки полів об'єкта.

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

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

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

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