Hexagonal Architecture - Driven Adapter Integration Testing
I made mistakes when doing Integration Testing on Driven Adapters that were connecting to External Systems. I'll share the problems and solutions here.
When reading Hexagonal Architecture (Alistair Cockburn), we see how to test the Hexagon… but how can we test the Driven Adapters? This question troubled me for years. I went through a lot of trial-and-error to discover the effective approach.
I thought ALL Integration Tests should include I/O
When connecting to I/O sources, we use Driven Adapters, which integrate with the I/O source. The Driven Adapter does some translation work, calls the I/O source, and then does that translation again.
Internal I/O Driven Adapters
These Driven Adapters connect to the I/O that is owned by our microservice. For example, we have the OrderRepository
(driven port), which is implemented by the PostgresOrderRepository
(driven adapter). The Driven Adapter integrates with our Postgres database using ORM and/or SQL queries and/or stored procedures.
When doing Integration Tests for the PostgresOrderRepository
, the test should span the Postgres Database. This means running the Postgres database locally, on our Test Server, or even better, running Postgres with Testcontainers.
External I/O Driven Adapters
These Driven Adapters connect to stuff that is not owned by our microservice. For example, we have the PaymentGateway
(driven port), which is implemented by the PayPalPaymentGateway
(driven adapter), which integrates with PayPal by making HTTP calls to the PayPal REST API.
When doing Integration Testing for the PayPalPaymentGateway
, I (and many other developers) thought that we should integrate it with PayPal's REST API. This means running an External System Test Instance on our Test Server, or connecting to the Test Instance provided by the third-party vendor. In the case of PayPal, it means using the PayPal sandbox.
Thus, like many other developers, I thought that to test Driven Adapters, we should truly connect to the Test Instance of that I/O source.
But I was wrong (in the case of External Systems)
Fortunately, Integration Testing for Internal I/O Driven Adapters worked out well.
But Integration Testing for External I/O Driven Adapters was a nightmare! The mistake I made was including the External System Test Instance in the Integration Test itself, and that’s a mistake I’ve seen so many others developers make as well - due to fallacies in widespread notions of integration testing.
I’m now going to reveal to you:
The 5 problems of mainstream Integration Testing for Driven Adapters
The solution I discovered to overcome this problem ⬇️⬇️⬇️