Назад к вопросам
Middle
154
questionbank

Что такое Mock, Stab и Spy в контексте тестирования программного обеспечения?

Sobes Copilot

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

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

sobes.tech AI

  • Mock (Мок): Поддельный объект, который проверяет, что тестируемый код взаимодействует с ним ожидаемым образом (вызывает определенные методы, с определенными аргументами и в нужном порядке). Моки проверяют поведение.
  • Stub (Стаб): Поддельный объект, который предоставляет заранее заданные ответы на вызовы методов. Стабы используются для управления состоянием зависимостей и фокусируются на тестируемом объекте, а не на взаимодействии с зависимостями. Стабы проверяют состояние.
  • Spy (Шпион): Частично поддельный объект, который оборачивает реальный объект. Он позволяет отслеживать вызовы его методов (аргументы, количество вызовов и т.д.), при этом реальный метод может быть вызван. Шпионы хороши для проверки того, что реальный объект был использован, и при этом позволяют проверить его поведение.
Тип Основное назначение Проверяет
Mock Проверка взаимодействия Поведение
Stub Предоставление данных Состояние
Spy Отслеживание вызовов реального объекта Поведение и состояние
// Пример использования Mock с Mockito
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import static org.mockito.Mockito.*;

public class ServiceTest {

    @Mock
    private Dependency dependencyMock;

    private Service service;

    @BeforeEach
    void setUp() {
        MockitoAnnotations.openMocks(this);
        service = new Service(dependencyMock);
    }

    @Test
    void shouldCallDependencyMethod() {
        service.doSomething();
        // Проверяем, что метод dependencyMethod был вызван один раз
        verify(dependencyMock, times(1)).dependencyMethod();
    }
}

class Service {
    private final Dependency dependency;

    public Service(Dependency dependency) {
        this.dependency = dependency;
    }

    public void doSomething() {
        dependency.dependencyMethod();
    }
}

class Dependency {
    public void dependencyMethod() {
        // Реальная логика
    }

    public String getData() {
        return "real data";
    }
}
// Пример использования Stub с Mockito
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;

public class AnotherServiceTest {

    @Mock
    private Dependency dependencyStub;

    private AnotherService anotherService;

    @BeforeEach
    void setUp() {
        MockitoAnnotations.openMocks(this);
        anotherService = new AnotherService(dependencyStub);
    }

    @Test
    void shouldReturnStubbedData() {
        // Задаем предопределенный ответ для метода getData()
        when(dependencyStub.getData()).thenReturn("stubbed data");

        String result = anotherService.processData();

        // Проверяем, что сервис возвращает данные из стаба
        assertEquals("processed stubbed data", result);
    }
}

class AnotherService {
    private final Dependency dependency;

    public AnotherService(Dependency dependency) {
        this.dependency = dependency;
    }

    public String processData() {
        String data = dependency.getData();
        return "processed " + data;
    }
}
// Пример использования Spy с Mockito
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Spy;
import org.mockito.MockitoAnnotations;

import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class YetAnotherServiceTest {

    @Spy
    private Dependency dependencySpy = new Dependency(); // Шпионы оборачивают реальный объект

    private YetAnotherService yetAnotherService;

    @BeforeEach
    void setUp() {
        MockitoAnnotations.openMocks(this);
        yetAnotherService = new YetAnotherService(dependencySpy);
    }

    @Test
    void shouldCallRealAndStubPartial() {
        // Можно вызвать реальный метод
        yetAnotherService.callSpyMethod();
        // И проверить, что он был вызван
        verify(dependencySpy, times(1)).dependencyMethod();

        // Можно переопределить поведение для конкретного метода
        when(dependencySpy.getData()).thenReturn("stubbed data for spy");
        String result = yetAnotherService.getDataFromSpy();

        // Проверяем, что вернулись переопределенные данные
        assertEquals("stubbed data for spy", result);

        // При этом можно проверить, что getData() был вызван
        verify(dependencySpy, times(1)).getData();
    }
}

class YetAnotherService {
    private final Dependency dependency;

    public YetAnotherService(Dependency dependency) {
        this.dependency = dependency;
    }

    public void callSpyMethod() {
        dependency.dependencyMethod();
    }

    public String getDataFromSpy() {
        return dependency.getData();
    }
}