Назад к вопросам
Junior
144
questionbank

Что такое мок (mock) в тестировании?

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

Мок (mock) — это объект-заглушка, полностью имитирующий поведение реального зависимого компонента или сервиса в тестовой среде. Он позволяет контролировать возвращаемые значения методов зависимостей и проверять, как тестируемый код с ними взаимодействует.

Основные отличия от других тестовых заглушек (Stubs, Fakes):

  • Stub (заглушка): Предоставляет предопределенные ответы на вызовы методов, но не проверяет взаимодействие.
  • Fake (фейк): Имеет работающую, но упрощенную реализацию зависимого компонента.
  • Mock (мок): Имитирует поведение, предоставляет предопределенные ответы и, самое главное, позволяет верифицировать, как тестируемый код взаимодействовал с этим объектом (например, какие методы были вызваны, сколько раз, с какими аргументами).

Назначения:

  • Изоляция тестируемого кода от внешних зависимостей (баз данных, внешних сервисов, файловой системы и т.д.).
  • Ускорение выполнения тестов.
  • Тестирование граничных случаев и обработки ошибок, которые сложно воспроизвести с реальными зависимостями.
  • Верификация ожидаемого взаимодействия между объектами.

Пример использования с Mockito:

// Интерфейс, который будет мокироваться
public interface UserService {
    User findUserById(long userId);
}

// Класс, который использует UserService и будет тестироваться
public class UserController {
    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    public String getUserName(long userId) {
        User user = userService.findUserById(userId);
        if (user != null) {
            return user.getName();
        }
        return "User not found";
    }
}

// Тестовый класс с использованием моков
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;

public class UserControllerTest {

    @Test
    void getUserName_UserFound() {
        // Создаем мок объекта UserService
        UserService mockUserService = mock(UserService.class);

        // Определяем поведение мока: при вызове findUserById(1), вернуть User
        User mockUser = new User(1, "John Doe");
        when(mockUserService.findUserById(1)).thenReturn(mockUser);

        // Создаем тестируемый объект, передавая ему мок
        UserController userController = new UserController(mockUserService);

        // Вызываем метод, который тестируем
        String userName = userController.getUserName(1);

        // Проверяем результат
        assertEquals("John Doe", userName);

        // Верифицируем, что метод findUserById был вызван один раз с аргументом 1
        verify(mockUserService, times(1)).findUserById(1);
    }

    @Test
    void getUserName_UserNotFound() {
        UserService mockUserService = mock(UserService.class);

        // Определяем поведение мока: при вызове findUserById(любой long), вернуть null
        when(mockUserService.findUserById(anyLong())).thenReturn(null);

        UserController userController = new UserController(mockUserService);

        String userName = userController.getUserName(2);

        assertEquals("User not found", userName);

        // Верифицируем, что метод findUserById был вызван один раз
        verify(mockUserService, times(1)).findUserById(anyLong());
    }

    // Вспомогательный класс для примера
    static class User {
        private final long id;
        private final String name;

        public User(long id, String name) {
            this.id = id;
            this.name = name;
        }

        public long getId() { return id; }
        public String getName() { return name; }
    }
}