TDD and Hexagonal Architecture – Unit Testing Use Cases
January 28, 2022
Blog > Development, Hexagonal Architecture, TDD | Valentina Cupać
TDD and Hexagonal Architecture – Unit Testing Use Cases
Is your job just to write some code? Or to build a system that helps users achieve their goals?
Use Case Driven Development (UCDD) is about using use cases to drive development. On one hand, we have actors, who want to achieve a goal. On the other hand, we have the system we’re building. Actors interact with the system to achieve their goals.
Suppose we have a bank. The customer may want to open up a bank account, withdraw funds, deposit funds. The loan officer may want to approve some loans. The bank manager may want to see monthly reports. All of these actors have some goals – and they achieve their goals by interacting with the bank system.
But the bank system is a black-box for them. For example, when we want to open up a bank account, the request data we provide is our name, address, date of birth, etc. The response we get from the bank is a bank number. When we deposit funds, our request data is the deposit amount and the response data we get from the bank system is the updated balance.
But do we, as the customer, know what’s happening inside the bank? Do we have access to the bank’s back-office? Can we just walk into the rooms where they store their paperwork?
No.
The bank provides us with a facade only. The bank representatives sitting at the counter are a facade. The online banking UI that we access is another facade. We only know about the facade, nothing else.
This is the essence of Hexagonal Architecture & Clean Architecture:
– We have the application core, which is isolated from the external world.
– We have primary actors (e.g. users) who want to execute use cases with our application (e.g. via UI, REST API…).
– We have secondary actors, representing external systems that our application needs to interact with (e.g. integrating with ERP).
– Our application is isolated from any infrastructure concerns (unaware of DB, files, network, etc.)
Use cases represent application logic, the application workflow. Use cases internally may call entities to execute business logic.
The unit tests we write are able to execute the use cases.
But wait for a second, it could mean that we could test acceptance criteria at the unit level too?
Yes, we can unit test the application logic (and indirectly the domain logic), and swap out shared dependencies (DB, file, network) with test doubles.
And since the tests are unit tests, running isolated in memory, we can get really fast feedback and high coverage of scenarios. In that case, we become less reliant on the E2E acceptance tests.