A few days ago Simon Brown posted a thoughtful piece called “Package by component and architecturally-aligned testing.” The first part of the post discusses the tensions between the common packaging approaches package-by-layer and package-by-feature. His conclusion, that neither is the right answer, is supported by a quote from Jason Gorman (that expresses the essence of thought over dogma):
The real skill is finding the right balance, and creating packages that make stuff easier to find but are as cohesive and loosely coupled as you can make them at the same time
Simon then introduces an approach that he calls package-by-component, where he describes a component as:
a combination of the business and data access logic related to a specific thing (e.g. domain concept, bounded context, etc)
By giving every component a public interface and package-protected implementation, any feature that needs to access data related to that component is forced to go through the public interface of the component that ‘owns’ the data. No direct access to the data access layer is allowed. This is a huge improvement over the frequent spaghetti-and-meatball approach to encapsulation of the data layer. I like this architectural approach. It makes things simpler and safer. But Simon draws another implication from it:
how we mock-out the data access code to create quick-running “unit tests”? The short answer is don’t bother, unless you really need to.
I tweeted that I couldn’t agree with this, and Simon responded:
This is a topic that polarises people and I’m still not sure why
I’m going to invoke the rule of 3 to try and lay out why I disagree with Simon.
The main benefit of automated tests is that you get feedback quickly when something has gone wrong. The longer it takes to run the tests, the longer […]
The ‘Testing Pyramid’ is often trotted out to illustrate a suggested distribution of tests. More small “unit” tests; less deep “end-to-end” tests. And various people have observed common anti-patterns, specifically the Ice Cream Cone, where there are lots of end-2-end tests and hardly any unit tests.
The anti-pattern that I see most often is the Beer Belly. This stems from a misunderstanding of what constitutes a unit test. It’s proven difficult to define exactly what a unit test is, but Mike Feathers described what ISN’T a unit test – notably tests that hit the network, the file system or the database. Most developers don’t seem to have taken this on board and write many tests that rely on some (or all) of these external components.
Combine this tendency to write integration tests instead of unit tests with a whole pile of manual test scripts and you get the classic beer belly topped with a big, cloudy head of woe.
And you know the best way to cure a hangover. Hair of the dog, anyone?