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

На монолитах или микросервисах написаны тесты

3.0 Senior🔥 141 комментариев
#REST API и микросервисы

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

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

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

# На монолитах или микросервисах написаны тесты

Ответ: Тесты пишутся и на монолитах, И на микросервисах. Но подходы, техники и инструменты существенно отличаются.

Пирамида тестирования (одинакова везде)

       End-to-End
           /\\
          /  \\
         /    \\          (20% - дорого, медленно)
        /______\\
       Integration
           /\\
          /  \\
         /    \\          (30% - среднее)
        /______\\
        Unit
       /      \\
      /        \\      (50% - быстро, дешево)
     /__________\\

Эта пирамида применима и к монолитам, и к микросервисам.

Тестирование на монолитах

Характеристики

  • Всё в одном процессе - все слои (вебд, бизнес-логика, БД) доступны
  • Проще unit тесты - можно инстанцировать классы напрямую
  • Integration тесты дешевле - нет сетевых вызовов между сервисами
  • End-to-end тесты - от HTTP запроса до БД, все внутри одного приложения

Пример: Монолитное приложение

// Монолитная архитектура
// PaymentService -> OrderService -> DatabaseLayer
// Всё в одном JAR файле

@SpringBootTest
public class OrderServiceTest {
    @Autowired
    private OrderService orderService;
    
    @Autowired
    private PaymentService paymentService;
    
    @Autowired
    private OrderRepository orderRepository;
    
    @Test
    public void testCreateOrder() {
        // Unit + Integration тест
        // Тестируем весь путь от сервиса до БД
        Order order = orderService.createOrder(1L, "Item");
        
        assertTrue(orderRepository.findById(order.getId()).isPresent());
        assertTrue(paymentService.isPaid(order.getId()));
    }
}

// Быстро, легко, не нужны моки

Преимущества тестирования на монолитах

  1. Простота - не нужно управлять сетевыми вызовами
  2. Скорость - тесты быстрые, всё локально
  3. Интеграция - легко тестировать взаимодействие модулей
  4. Отладка - просто отладить в IDE

Недостатки

  1. Масштабируемость - монолит растёт, тесты становятся медленнее
  2. Изоляция - сложно тестировать отдельные компоненты
  3. Зависимости - один баг может сломать множество тестов

Тестирование на микросервисах

Характеристики

  • Сервисы независимы - каждый в своем процессе
  • Сетевые границы - нужно мокировать другие сервисы
  • Unit тесты сложнее - много внешних зависимостей
  • Integration тесты дороже - нужно запускать несколько сервисов
  • E2E тесты критичны - проверяют взаимодействие сервисов

Пример: Микросервисная архитектура

// Order Service (микросервис)
@RestController
@RequestMapping("/api/orders")
public class OrderController {
    @Autowired
    private OrderService orderService;
    
    @Autowired
    private PaymentServiceClient paymentClient;  // REST клиент
    
    @PostMapping
    public Order createOrder(@RequestBody OrderRequest request) {
        // Вызываем PaymentService по HTTP
        boolean paid = paymentClient.pay(request.getAmount());
        
        Order order = orderService.createOrder(request);
        order.setPaid(paid);
        return order;
    }
}

// Unit тест
@Test
public void testCreateOrderUnit() {
    // Мокируем внешний сервис
    PaymentServiceClient paymentClient = Mockito.mock(PaymentServiceClient.class);
    Mockito.when(paymentClient.pay(100)).thenReturn(true);
    
    OrderService orderService = new OrderService();
    Order order = orderService.createOrder("Item", paymentClient);
    
    assertNotNull(order);
}

// Integration тест (контейнер)
@SpringBootTest
@Testcontainers
public class OrderServiceIntegrationTest {
    @Container
    static PostgreSQLContainer<?> postgres = 
        new PostgreSQLContainer<>("postgres:13");
    
    @Test
    public void testCreateOrder() {
        // Тестируем Order Service + своя БД
        // PaymentService всё ещё замокирован
    }
}

// E2E тест (все сервисы)
@Test
public void testFullOrderFlow() {
    // docker-compose up (все микросервисы)
    // Отправляем HTTP запрос на Order Service
    // Order Service вызывает Payment Service
    // Проверяем результат в обеих БД
}

Стратегия тестирования микросервисов

УровеньГде писатьИнструменты
UnitВ каждом сервисеJUnit, Mockito, AssertJ
IntegrationВ каждом сервисеTestContainers, H2, MockServer
E2EОтдельный проектPlaywright, REST Assured, Testcontainers (compose)
ContractМежду сервисамиPact, Spring Cloud Contract

Contract Testing - ключевое отличие

В микросервисах критически важны контрактные тесты:

// Payment Service (провайдер)
@SpringBootTest
public class PaymentProviderTest {
    @Test
    @PactTestFor(providerName = "PaymentService", port = "8080")
    public void testPaymentEndpoint(PactVerificationContext context) {
        context.verifyInteraction();
    }
}

// Order Service (потребитель)
@PactTestFor(providerName = "PaymentService")
public class PaymentConsumerTest {
    @Pact(consumer = "OrderService", provider = "PaymentService")
    public RequestResponsePact createPact(PactDslWithProvider builder) {
        return builder
            .given("payment is available")
            .uponReceiving("a request to pay")
            .path("/api/pay")
            .willRespondWith()
            .status(200)
            .body("amount", 100)
            .toPact();
    }
}

Сравнение: Монолит vs Микросервисы

АспектМонолитМикросервисы
Unit тестыПростыеНужны моки внешних сервисов
IntegrationВсё внутриНужна оркестрация сервисов
E2EОдин процессРаспределённые системы
Скорость тестовБыстрыеМедленнее (сеть, контейнеры)
ИнструментыПростые (JUnit)Сложнее (Testcontainers, Pact)
Contract TestingНе нуженОБЯЗАТЕЛЕН

Лучшие практики для обеих архитектур

1. Следуй пирамиде тестирования

Много Unit → Меньше Integration → Мало E2E

2. Отделяй тесты по скорости

# Быстрые (run on every commit)
make test:unit        # < 5 сек

# Средние (run on PR)
make test:integration # < 30 сек

# Медленные (run on CI/CD)
make test:e2e         # < 5 мин

3. Используй тестовые контейнеры

// Гарантирует одинаковую окружение
@Container
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>();

4. Изолируй тесты

// Каждый тест - чистая БД
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)

Заключение

Тесты пишутся везде, но:

  • На монолитах - проще писать интеграционные тесты
  • На микросервисах - нужны контрактные тесты и сложная оркестрация
  • Unit тесты - везде критичны и доминируют по количеству
  • E2E тесты - на микросервисах сложнее и дороже

Выбор архитектуры серьёзно влияет на стратегию и инструменты тестирования, но сами тесты нужны в обоих случаях.