---
title: How Outside-In TDD Can Lead To More Modular Code
disqus: pierodibello
---
###### tags: `TDD`
# How Outside-In TDD Can Lead To More Modular Code
This video https://www.youtube.com/watch?v=rW0ZFhKGdoM
{%youtube rW0ZFhKGdoM %}
The Jason's Guitar Shack kata: https://codemanship.wordpress.com/2020/10/10/the-jasons-guitar-shack-kata-part-i-core-logic/
Repo for the java version: https://github.com/jasongorman/guitar_shack_java/
We have to develop an app that sends alerts when products needs restocking.
### Outside-in, starting from the outermost entry point
That style uses **stubs and mocks as placeholders for other parts of the design**: that allows me to work outside-in, from the entry point to the logic, with a **"fake it until I make it"** approach for other parts of the system that I don't want to focus on, **so I can focus on the solving one problem at a time**.
He starts from the `StockMonitor`, the outermost part of our system, the entry point...
In order to test-drive the `StockMonitor`, he stubs `ReorderLevel` and `Warehouse`, and mocks the `Alert` (because he needs to spy into it to check that the alarm has been sent).
Then he moves inward to test-drive the implementation of real `LeadTimeReorderLevel`, faking its collaborator `SalesRate`.
Then again he moves inward to test-drive the implementation of a real `ThirtyDayAverageSalesRate`.
At the end he codes the real implementations of `RecentSales` and `Warehouse` (`SalesData` and `ProductData`) which actually talks to external systems to fetch historical sales data and products stock data.
And so on, mocking and stubbing all the way down,
* **Working inwards from the outside one layer of design at a time**
* **Using test doubles so that we can solve one problem at a time.**
`SalesData` and `ProductData` both uses a `Client`, which has a concrete implementation as a `RESTClient`, which uses a Java-provided HTTP client.
A side effect of this outside-in approach, using test doubles to solve one problem at a time, is that the resulting code is **highly modular**:
* Each class does one thing.
* Most of the **dependencies are swappable** by dependency injection => loose coupling.
* All modules are **hiding their internal details** (excluding `Product`, which is a data class retrieved from the web...).
* Each interface has one method on it
- doing one thing only, a single easy contract
- tell don't ask
- faking it when test-driving the upper layer which uses it, deferring its implementation
### Code coverage
* high unit test coverage: 91% line coverage with unit tests, the `Web` class is not unit tested
* 100% line code coverage with all the test suite, including integration tests.
* the integration test covers 90% line coverage, because it's an **"happy path"** scenario
### Integration test (or should we say "acceptance test"?)
**The purpose of the integration tests is to touch as many parts of the code as possible**, to check that when we plug all the concrete stuff together, it's working as expected in a "happy path" scenario.
The integration test was written **after the fact**, and it was green at the first launch (sort of acceptance test?).
In the integration test is clear the composition of the whole app like the "Russian Dolls".

**Swappability** of components is a key benefit of this test-driven approach => it brings testability and flexibility (DIP, OCP).
This outside-in TDD style, with stubs and mocks as placeholder to allow you to make one thing at a time, can lead to highly modular design and highly testable. Also, this code is flexible, because of its modularity and composition.
### Contract tests
`SalesDataTestBase` has a contract test version and a unit test version.
I would call them "integration test", but I understand its role here is to check the contract between our system and external data providers (as in https://martinfowler.com/bliki/ContractTest.html).
The unit test can be green but the system not working because of a change in the contract! Those contract tests help me here.
Unit test green, contract test red => warning, maybe something changed on the APIs?
Those tests are useful for my dev team but also for the data providers' teams: they can run my contract tests to check that the expectations clients are making are satisfied by their services' API.
## Doubts / observations
* is `SalesDataUnitTest` (and `ProductDataUnitTest` BTW) a true *unit test*? Sure enough, it's fast, quite narrow-focused, and almost focusing on a single behavior. The "quite" and "almost" in my previous statement express my perplexity here: this test actually is also "testing" the real `RESTClient` with a fake JSON to deserialize using an external library (GSon).
* The `RESTClient` was refactored to extract away in other classes the lowest policies:
* `Network`, whose implementation (`Web`) actually executes an HTTP call
* `RequestBuilder`, a concrete class to create an HTTP request (not unit tested, but tested indirectly in other unit tests)
* The integration test uses a mock `Alarm` because he's not still implemented a *real* alarm service to send real notifications.
* He uses the integration test, `StockMonitorIntegrationTest`, as a sort of an "acceptance test", written at the end of the development to check that everything works together.