← Назад к вопросам

Что такое Stub?

1.3 Junior🔥 141 комментариев
#Тестирование

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое Stub в контексте разработки ПО и тестирования

Stub (заглушка) — это объект, который используется в модульном тестировании для подмены реальной зависимости с целью изоляции тестируемого кода и контроля над его взаимодействием с внешними компонентами. Это фундаментальное понятие в паттерне "Тестирование через изоляцию" (Isolated Testing), часто реализуемое с помощью библиотек для мокинга (Mocking).

Основное предназначение Stub

Stub создаётся для того, чтобы:

  • Имитировать поведение реального компонента (например, базы данных, веб-сервиса, файловой системы).
  • Возвращать предопределённые, "зашитые" (hard-coded) значения в ответ на вызовы его методов.
  • Убрать нестабильные, медленные или недоступные внешние зависимости из процесса тестирования.

Таким образом, Stub позволяет сосредоточиться на тестировании бизнес-логики конкретного класса или метода, не беспокоясь о корректности работы его окружения.

Ключевые характеристики Stub

  • Пассивный объект: Он не ведёт учёт вызовов и не проверяет, как его использовали. Его задача — просто предоставить ответ.
  • Предсказуемость: Всегда возвращает одни и те же данные, которые были заданы при его создании.
  • Упрощение тестов: Позволяет легко моделировать различные сценарии (успех, ошибки, пограничные значения) без настройки реальных систем.

Отличие Stub от Mock и других тестовых двойников (Test Doubles)

Важно различать Stub и Mock, так как эти термины часто путают (хотя многие современные фреймворки, например Moq или NSubstitute, стирают эту границу на практике).

  • Stub — это "дублёр для состояния". Он заменяет объект, чтобы предоставить тестовые данные.
  • Mock — это "дублёр для поведения". Он заменяет объект, чтобы проверить (верифицировать), как тестируемый код взаимодействовал с ним (например, был ли вызван метод с определёнными аргументами и сколько раз).

Другие типы тестовых двойников:

  • Fake — упрощённая, но рабочая реализация (например, репозиторий в памяти вместо базы данных).
  • Dummy — объект, который передаётся, но никогда не используется (просто для заполнения параметров).
  • Spy — записывает информацию о вызовах для последующей проверки, что-то среднее между Stub и Mock.

Практический пример в C#

Рассмотрим сервис OrderProcessor, который зависит от репозитория IOrderRepository и внешнего платёжного шлюза IPaymentGateway.

// Интерфейс зависимости
public interface IShippingService
{
    decimal CalculateShippingCost(string city);
}

// Класс, который мы тестируем
public class OrderCalculator
{
    private readonly IShippingService _shippingService;

    public OrderCalculator(IShippingService shippingService)
    {
        _shippingService = shippingService;
    }

    public decimal GetTotalAmount(decimal productPrice, string city)
    {
        var shippingCost = _shippingService.CalculateShippingCost(city);
        return productPrice + shippingCost;
    }
}

Без Stub тест зависел бы от реальной службы доставки. С использованием Stub (через библиотеку Moq):

using Moq;
using Xunit;

public class OrderCalculatorTests
{
    [Fact]
    public void GetTotalAmount_ForMoscow_AddsFixedShippingCost()
    {
        // 1. ARRANGE: Создаём и настраиваем Stub
        var shippingServiceStub = new Mock<IShippingService>();
        // Жёстко задаём возвращаемое значение для конкретного вызова
        shippingServiceStub.Setup(s => s.CalculateShippingCost("Moscow"))
                           .Returns(500m); // Предопределённая стоимость

        var calculator = new OrderCalculator(shippingServiceStub.Object);

        // 2. ACT: Выполняем тестируемый метод
        var total = calculator.GetTotalAmount(1000m, "Moscow");

        // 3. ASSERT: Проверяем результат, используя известное значение из Stub
        Assert.Equal(1500m, total); // 1000 (товар) + 500 (доставка из Stub)
    }

    [Fact]
    public void GetTotalAmount_ForRemoteCity_AddsIncreasedShippingCost()
    {
        // Stub позволяет легко смоделировать другой сценарий
        var shippingServiceStub = new Mock<IShippingService>();
        shippingServiceStub.Setup(s => s.CalculateShippingCost("Vladivostok"))
                           .Returns(1500m);

        var calculator = new OrderCalculator(shippingServiceStub.Object);

        var total = calculator.GetTotalAmount(1000m, "Vladivostok");

        Assert.Equal(2500m, total);
    }
}

Преимущества использования Stub

  • Скорость: Тесты выполняются мгновенно, так как нет сетевых вызовов или операций ввода-вывода.
  • Надёжность: Тесты не ломаются из-за сбоев во внешних системах.
  • Детерминированность: Результат теста всегда одинаков для одних и тех же входных данных.
  • Фокус на Unit: Позволяет строго придерживаться принципа модульного тестирования одного компонента за раз.
  • Простота моделирования сценариев: Легко протестировать обработку исключений, возврат null или пограничных значений.

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

Stub идеально подходит для:

  • Тестирования алгоритмов, которые используют результаты вызовов внешних зависимостей.
  • Моделирования редких или сложно воспроизводимых состояний внешней системы (например, таймаут, ошибка 500).
  • Ранней разработки, когда реальная зависимость ещё не готова (реализация по контракту интерфейса).

Заключение

Stub — это мощный и элегантный инструмент в арсенале разработчика, следующий принципам SOLID, в частности Принципу инверсии зависимостей (DIP). Он позволяет писать быстрые, стабильные и содержательные unit-тесты, что напрямую влияет на качество кода и снижение количества дефектов. Понимание разницы между Stub, Mock и другими двойниками помогает выбирать правильный инструмент для каждой задачи тестирования, делая процесс более осознанным и эффективным.

Что такое Stub? | PrepBro