Optivem Journal

Optivem Journal

Hexagonal Architecture

Hexagonal Architecture: Do NOT mock everything

Stop Mocking. Use Fakes, Stubs, and Spies Instead.

Valentina Jemuović's avatar
Valentina Jemuović
Feb 19, 2026
∙ Paid

📅 Join me for Acceptance Testing (Live Training) on Wed 25th Feb (17:00 - 19:00 CET) (100% discount for Optivem Journal members)


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


The most common mistake in Hexagonal Architecture is mocking everything outside the domain.

Tests break after the tiniest change.

Refactors become nightmares.

And your “clean architecture” is now just a pile of mocks.

❌ Over-Mocking Everything

Okay, Order Service Test… let’s mock all the driven ports:

- Repository? mock
- Payment Gateway? mock
- Email Service? mock

By the time your test runs, it’s fragile spaghetti:

  • Change a method signature in the repository? Test fails.

  • Change a method signature in the payment gateway? Test fails.

In the repository, I had a method add(int id, OrderData data). I refactored it to be add(Order order)… tests fail because the mock is now out-of-date.

In the payment gateway, I used the method getAllInvoices() and then did in-memory filtering to find an invoice. In my source code I decided to use the method getInvoice(String invoiceId)… tests fail because the mock now is out-of-date.

You now have hexagonal architecture… and 47 failing tests.

Why it’s bad:

  • Tests describe implementation, not behavior

  • Ports are treated as a checklist of mocks, not boundaries

  • Refactoring domain logic becomes a nightmare

  • Cognitive load goes through the roof

✅ Testing What Matters

Focus on behavior, not mocks:

  • ✅ Fakes

  • ✅ Stubs

  • ✅ Spies

  • ❌ Mocks

For the same Order Service:

- Repository → in-memory fake
- Payment Gateway → simple stub that can be configured to maybe payment succeed or fail
- Email Service → spy, whereby we collect emails in a queue, and inspect emails sent

Notice the difference?

  • Tests now describe what the domain does, not how infrastructure works.

  • Refactoring domain code rarely breaks tests.

  • Cognitive load drops — you’re testing one thing at a time.

Fake data, not behavior. Test behavior, not calls.

💡Order Test Without Mock Overload

This post is for paid subscribers

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