Optivem Journal

Optivem Journal

Hexagonal Architecture

Modern Hexagonal Architecture: Testing for Backend

How can we test the Backend?

Valentina Jemuović's avatar
Valentina Jemuović
Nov 28, 2025
∙ Paid

🚀 Join the ATDD Accelerator waitlist


🔒 Hello, this is Valentina with a premium issue of the Optivem Journal. I help Engineering Leaders & Senior Software Developers apply TDD in Legacy Code.


Backend Component Tests

Backend Component Tests verify whether the Backend as a whole, works correctly (this spans all logic - presentation, business, infrastructure logic). They:

  • Target the Backend API

  • Stub out External Systems

These tests are agnostic to the architecture inside the Backend. It doesn’t matter whether the Backend is a Big Ball of Mud, or Hexagonal Architecture, or Vertical Architecture, etc. The Component Tests don’t care, they don’t know, because they are blackbox tests - they are testing the Backend as a blackbox.

Example: OrderControllerTest sets up the Stripe WireMock Stub that it returns some invoice number, we call the Backend REST API endpoint POST /api/orders with request body { sku=ABC, quantity=4 }, and then verify that it returns an order number.

In Legacy Code, we can write Component Tests from Day 1.

Backend Hexagonal Architecture Testing

If the Backend is structured using Hexagonal Architecture, then we can go a level down, to do this kind of testing:

  1. Unit Tests - testing the Hexagon

  2. Narrow Integration Tests - testing the Adapters

Note: In Legacy Code, if your Backend is a Big Ball of Mud, you’ll you need to have Component Tests first, then you’ll be able to safely redesign your Backend from Big Ball of Mud towards Hexagonal Architecture, and then you’ll be able to introduce these tests.

Unit Tests - Hexagon

Unit Tests verify Business Logic. They:

  • Target Driving Ports

  • Stub out Driven Ports

Therefore, they span the Hexagon, i.e. testing the Hexagon in isolation.

Example I: With coarse-grained ports (Application Services): OrderServiceTest tests the business logic inside OrderService, whilst stubbing out the OrderRepository.

Example II: With fine-grained ports (Request Handlers): PlaceOrderTest tests the business logic inside PlaceOrderHandler, whilst stubbing out the OrderRepository.

Narrow Integration Tests - Driving Adapters

Driving Adapter Narrow Integration Tests verify Presentation Logic. They:

  • Target Driving Adapters

  • Stub out Driven Ports

Therefore, they span the Driving Adapters, i.e. testing the Driving Adapters in isolation.

Example: OrderControllerTest tests the presentation logic inside the OrderController, e.g. how it maps success/failure to http status codes and responses.

Narrow Integration Tests - Driven Adapters

Driven Adapter Narrow Integration Tests verify Infrastructure Logic. They:

  • Target Driven Adapters via Driven Ports

  • Stub out External Systems

Therefore, they span the Driven Adapters, i.e., testing the Driven Adapters in isolation.

Example I: OrderRepositoryTest tests the infrastructure logic of the OrderRepository. It’s executed against the SqlOrderRepository (using real DB) and the FakeOrderRepository adapters.

Example II: PaymentGatewayTest tests the infrastructure logic of the PaymentGateway. It’s executed against the StripePaymentGateway (using WireMock instead of Stripe API) and the FakePaymentGateway adapters.


Real-life Example: Ordering System

For an e-commerce system:

This post is for paid subscribers

Already a paid subscriber? Sign in
© 2025 Valentina Jemuović, Optivem
Privacy ∙ Terms ∙ Collection notice
Start your SubstackGet the app
Substack is the home for great culture